Difference between set with {merge: true} and update

The way I understood the difference:

  • set without merge will overwrite a document or create it if it doesn't exist yet

  • set with merge will update fields in the document or create it if it doesn't exists

  • update will update fields but will fail if the document doesn't exist

  • create will create the document but fail if the document already exists

There's also a difference in the kind of data you provide to set and update.

For set you always have to provide document-shaped data:

set(
  {a: {b: {c: true}}},
  {merge: true}
)

With update you can also use field paths for updating nested values:

update({
  'a.b.c': true
})

Another difference (extending Scarygami's answer) between "set with merge" and "update", is when working with a nested values.

if you have a document structured like this:

 {
   "friends": {
     "friend-uid-1": true,
     "friend-uid-2": true,
   }
 }

and want to add {"friend-uid-3" : true}

using this:

db.collection('users').doc('random-id').set({ "friends": { "friend-uid-3": true } },{merge:true})

will result in this data:

 {
   "friends": {
     "friend-uid-1": true,
     "friend-uid-2": true,
     "friend-uid-3": true
   }
 }

however update using this:

db.collection('users').doc('random-id').update({ "friends": { "friend-uid-3": true } })

will result in this data:

 `{
   "friends": {
     "friend-uid-3": true
   }
 }`

Per docs: https://firebase.google.com/docs/firestore/manage-data/add-data#update_fields_in_nested_objects

Dot notation allows you to update a single nested field without overwriting other nested field. If you update a nested field without dot notation, you will overwrite the entire map field.

As stated above, this replaces entire friends structure.

db.collection('users').doc('random-id').update({
    "friends": {
        "friend-uid-3": true
    }
})

This does not.

db.collection('users').doc('random-id').update({
    "friends.friend-uid-3": true
})