0

So I have a emojiCounter field which is used to store an array of objects like

emojiCounter : [{emoji : 'haha', by : 'user1'},{emoji : 'haha', by : 'user2'}]

But I am trying to figure out how to update an object if a user repeatedly selects different emoji cause in that case I only have to update the emoji by userName

KALITA
  • 716
  • 2
  • 8
  • 20

1 Answers1

1

Since emojiCounter is an array of Objects, you need to first read the Array, update it in the frontend then save it back to Firestore. Using the array-union() method will not work, because it is an array of Objects.

You can verify that with the following code. The objects are added, not updated.

  const db = firebase.firestore();
  const docRef = db.collection('testSO').doc('testSO');

  const emojiCounter = [
    { emoji: 'haha', by: 'user1' },
    { emoji: 'haha', by: 'user2' },
  ];

  docRef
    .set({ emojiCounter })
    .then(() => {
      return docRef.get();
    })
    .then((doc) => {
      console.log('#1', doc.data().emojiCounter);

      return docRef.update({
        emojiCounter: firebase.firestore.FieldValue.arrayUnion({
          emoji: 'hoho',
          by: 'user1',
        }),
      });
    })
    .then(() => {
      return docRef.get();
    })
    .then((doc) => {
      console.log('#2', doc.data().emojiCounter);

      return docRef.update({
        emojiCounter: firebase.firestore.FieldValue.arrayUnion({
          emoji: 'hihi',
          by: 'user2',
        }),
      });
    })
    .then(() => {
      return docRef.get();
    })
    .then((doc) => {
      console.log('#3', doc.data().emojiCounter);
    });

Note that you may encounter a problem with the solution described above, because, depending on your app functions, it may imply that user1 could change the emoji value of user2. If you want to avoid that, you should adopt another approach. For example allow the user to only update his emoji (e.g. with one emoji doc per user) and have a Cloud Function, triggered when one of those docs is updated, and which updates a central document which contains the array. You should use a Transaction to perform the update.


Also, since you are using one array that contains the emojis of all users, note the maximum size of a field value: 1,048,487 bytes.

Renaud Tarnec
  • 79,263
  • 10
  • 95
  • 121
  • Well thanks for your answer, but I decided to make `emojiCounter` a collection as it will be reliable and efficient in my way and as you said `maximum size of a field value: 1,048,487 bytes` so it would be disastrous if the number of reactors exceeds that limit – KALITA Mar 06 '21 at 15:26
  • Yes, IMHO it is the good approach. I actually wrote the two last remarks in my answer with that in mind :-) Having a Cloud Function, triggered when one of those docs is updated, and which updates a central document with one or more fields may still be interesting if you need to frequently read **all** the emoji values: only one document read instead of all the collection read. – Renaud Tarnec Mar 06 '21 at 15:29
  • I would love to use that but since the cloud functions are no longer free, that's the problem and tbh I don't have any money to invest in G-Cloud – KALITA Mar 06 '21 at 16:19
  • 1
    See https://stackoverflow.com/questions/62824043/is-function-cloud-in-firebase-free-or-not-cloud-functions-deployment-requires-t – Renaud Tarnec Mar 06 '21 at 16:20
  • yep but I don't have any card rn, maybe I will try it out in the near future – KALITA Mar 06 '21 at 17:20