2

In My Cloud Firestore database structure looks like this. Now, I'd like to delete index positions based on Index 0, Index 1 like this.

const arrayLikedImagesRef = {imageurl: image, isliked: true};
  const db = firebase.firestore();
  const deleteRef = db.collection('userdata').doc(`${phno}`);
  deleteRef.update({
    likedimages: firebase.firestore.FieldValue.arrayRemove(arrayLikedImagesRef)
  });
});

enter image description here

Romeo Ninov
  • 6,538
  • 1
  • 22
  • 31

2 Answers2

2

As explained here, “bad things can happen when trying to update or delete array elements at specific indexes”. This is why the Firestore official documentation indicates that the arrayRemove() function will take elements (strings) as arguments, but not indexes.

As suggested in this answer, if you prefer using indexes then you should get the entire document, get the array, modify it and add it back to the database.

PYB
  • 503
  • 6
  • 20
0

You can't use FieldValue to remove array items by index. Instead, you could use a transaction to remove the array items. Using a transaction ensures you are actually writing back the exact array you expect, and can deal with other writers.

For example (the reference I use here is arbitrary, of course, you would need to provide the correct reference):

db.runTransaction(t => {
  const ref = db.collection('arrayremove').doc('targetdoc');

  return t.get(ref).then(doc => {
    const arraydata = doc.data().likedimages;

    // It is at this point that you need to decide which index
    // to remove -- to ensure you get the right item.
    const removeThisIndex = 2;

    arraydata.splice(removeThisIndex, 1);
    t.update(ref, {likedimages: arraydata});
  });
});

Of course, as noted in the above code, you can only be sure you are about to delete the correct index when you are actually inside the transaction itself -- otherwise the array you fetch might not line up with the array data that you originally selected the index at. So be careful!


That said, you might be asking what to do given that FieldValue.arrayRemove doesn't support nested arrays (so you can't pass it multiple maps to remove). In that case, you just want a variant of the above that actually checks values (this example only works with a single value and a fixed object type, but you could easily modify it to be more generic):

const db = firebase.firestore();
const imageToRemove = {isliked: true, imageurl: "url1"};

db.runTransaction(t => {
  const ref = db.collection('arrayremove').doc('byvaluedoc');
  return t.get(ref).then(doc => {
    const arraydata = doc.data().likedimages;
    const outputArray = []
    arraydata.forEach(item => {
      if (!(item.isliked == imageToRemove.isliked &&
            item.imageurl == imageToRemove.imageurl)) {
           outputArray.push(item);
          }
    });
    t.update(ref, {likedimages: outputArray});
  });
});

(I do note that in your code you are using a raw boolean, but the database has the isliked items as strings. I tested the above code and it appears to work despite that, but it'd be better to be consistent in your use of types).

robsiemb
  • 6,157
  • 7
  • 32
  • 46