mchristos
mchristos

Reputation: 1909

Write document with "new" field if not exists, else merge fields

Using a firebase function, I'm polling an API every x minutes for a set of items which I keep my firestore. Say each item look like this:

{ name: "John", id: 1}

If this is a new document, I would like to store it in firestore with a state field with value "New":

[1]: { name: "John", state: "New"}

However, if I've seen this document before (its in the firestore with that id), I would like to update the data inside, but leave the state untouched, i.e

Before:

[1]: { name: "John", state: "Processed"}

After:

[1]: {name: "UpdatedName", state: "Processed"}

How can I achieve this? For documents that already exist I can achieve this using the mergeFields SetOption so exclude the state field - but unfortunately brand new documents that arrive then are not set with state: "New".

The other option is to check with firebase if the id exists for each document, but this seemed less than ideal and was awkward to achieve (I ended up making multiple queries in a foreach loop). This is roughly my code:

const batch = db.batch();
response.data.items.forEach(item => {
  const document = {
    name: item.name
    state: "New"
  };
  batch.set(
    db.collection(collectionPath).doc(item.id),
    document,
    {
      mergeFields: Object.keys(document).filter(
        field => field !== 'state'
      ),
    }
  );
});
return batch.commit();

Upvotes: 2

Views: 496

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 599631

Since the new state of the document on the existing state (or lack thereof) of the document, you'll need to execute a transaction here.

let docRef = db.collection(collectionPath).doc(item.id);
let transaction = db.runTransaction(t => {
  return t.get(docRef)
    .then(doc => {
      if (doc.exists()) {
         t.update(docRef, { state: "Processed" });
      }
      else {
         t.set(docRef, { name: "John", state: "New" });
      }
    });
}).then(result => {
  console.log('Transaction success!');
}).catch(err => {
  console.log('Transaction failure:', err);
});

Upvotes: 2

Related Questions