16

I have a document in Firebase Firestore that is something like the below. The main point here is that I have an array called items with objects inside it:

{
 name: 'Foo',
 items: [
   {
     name: 'Bar',
     meta: {
        image: 'xyz.png',
        description: 'hello world'
     }
   },
   {
     name: 'Rawr',
     meta: {
        image: 'abc.png',
        description: 'hello tom'
     }
   }
 ]
}

I am trying to update a field inside the item array, under the meta object. For example items[0].meta.description from hello world to hello bar

Initially I attempted to do this:

  const key = `items.${this.state.index}.meta.description`
  const property = `hello bar`;

  this.design.update({
    [key]: property
  })
  .then(() => {
    console.log("done")
  })
  .catch(function(error) {
    message.error(error.message);
  });

This didn't appear to work though, as it removed everything in the item index I wanted to modify, and just kept the description under the meta object

I am now trying the following which basically rewrites the whole meta object with the new data

  const key = `items.${this.state.index}.meta`
  const property = e.target.value;
  let meta = this.state.meta;
  meta[e.target.id] = property;

  this.design.update({
    [key]: meta
  })
  .then(() => {
    this.setState({
    [key]: meta
    })
  })
  .catch(function(error) {
    message.error(error.message);
  });

Unfortunately though, this seems to turn my whole items array into an object that looks something like:

{
 name: 'Foo',
 items: {

   0: {
     name: 'Bar',
     meta: {
        image: 'xyz.png',
        description: 'hello world'
     }
   },
   1: {
     name: 'Rawr',
     meta: {
        image: 'abc.png',
        description: 'hello tom'
     }
   }
 }
}

Any ideas how I can just update the content I want to?

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
K20GH
  • 6,032
  • 20
  • 78
  • 118

2 Answers2

25

Firestore doesn't have the ability to update an existing element in an indexed array. Your only array options for updates are described in the documentation - you can add a new element to the array ("arrayUnion") or remove an element ("arrayRemove").

As an alternative, you can read the entire array out of the document, make modifications to it in memory, then update the modified array field entirely.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • 2
    "As an alternative, you can read the entire array out of the document, make modifications to it in memory, then update the modified array field entirely." What if some other user updates some other item of this array in time between my fetching - modification - update on server , won't it update the old array which was fetched by me initially with changes just made by me ? – Naveen Rao Mar 30 '20 at 09:31
  • 2
    Then use a transaction to read and write the document atomically. https://firebase.google.com/docs/firestore/manage-data/transactions – Doug Stevenson Mar 30 '20 at 16:06
  • 1
    @DougStevenson Regarding the options here, say I have an array of 500 entries. I could remove an entry and add an entry (2 writes) or simply replace the entire array (1 write). Would you know what's the better option here costs wise? Afaik, you want to keep your reads and writes to a minimum, but I'm also afraid that replacing an array with 500 entries of an object that itself is 15 lines will get very expensive. – Tim Jacobs May 16 '22 at 08:58
1

You can make a separate collection for that particular array, like this in this picture earlier I had different fields (no collections) of name, email and pages, And in this, I wanted to change the data of a specific page that is inside the array. For that, I made a different collection of pages with individual documents of each page having values of title description and content which can be mutated. new collection made for the pages array

Nimish
  • 35
  • 8