Search code examples
angularfirebasegoogle-cloud-firestoreangularfire2

Firestore - how to add/subtract from a map of values


I am following the Firestore instructions for storing arrays: https://firebase.google.com/docs/firestore/solutions/arrays

Now what I would like to do is push to this map. For example right now i have:

Contacts
   contact1: true

But I would like to add or remove a contact for example:

Contacts
   contact1: true
   contact2: true

I have tried getting the Contacts map and using the push method but I don't think this will work as it is not a traditional array. For example:

this.afs
  .doc(`groups/${group.id}`)
  .ref.get()
  .then(doc => {
    let contacts: Array<any> = doc.data().contacts;

    contacts.push({ // error here as push is not a function
      [contactId]: true
    });

    console.log(contacts);
  });

Is there an easier way to do this - am I missing something?


Solution

  • First, you can't use the push method on an object since the map is not an array.

    You can simply use the . or [] operators to access/add/update values of a map in JS.

    In cases of objects stored in firestore like Arrays and Objects, you can't really directly "push" values to them. You first need to get the document containing them and then update their value locally.

    After that is done, you update the value to the Firestore.

    To simplify the process, you can use the runTransaction() method provided by Firestore SDK or the Admin SDK if you are on Cloud Functions.

    Here's the code which will get the job done for you.

    const docRef = this.afs.doc(`groups/${groupId}`);
    
    db.runTransaction((t) => { // db is the firestore instance
      return t.get(docRef).then((doc) => { // getting the document from Firestore
        // {} is a fallback for the case if the "obj" is not present in the firestore
        const obj = doc.get("contacts") ? doc.get("contacts") : {};
        obj[contactId] = true; // updating the value here locally
    
        t.set(docRef, { contacts: obj }, { // updating the value to Firestore.
          merge: true,
        });
    
        return;
      }).then((result) => {
        console.log('map updated', result);
        return;
      }).catch((error) => handleError(error));
    });