使用 {merge: true} 设置 Firestore 和更新之间的区别

Difference Between Firestore Set with {merge: true} and Update

Cloud Firestore 中有三个写入操作:

  1. add()
  2. set()
  3. update()

文档中说使用 set(object, { merge: true }) 会将给定对象与现有文档合并。

当您使用 update(object) 时也会发生同样的情况...那有什么区别呢? google 会重复这样的功能似乎很奇怪。

我理解差异的方式:

  • set 没有 merge 将覆盖文档或创建文档(如果文档尚不存在)

  • setmerge 将更新文档中的字段或如果不存在则创建它

  • update 将更新字段,但如果文档不存在则会失败

  • create 将创建文档,但如果文档已存在则创建失败

您提供给 setupdate 的数据类型也有所不同。

对于set,您始终必须提供文档格式的数据:

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

通过 update,您还可以使用字段路径来更新嵌套值:

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

"set with merge" 和 "update" 之间的另一个区别(扩展 Scarygami 的回答)是在使用嵌套值时。

如果您的文档结构如下:

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

并想添加 {"friend-uid-3" : true}

使用这个:

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

将产生以下数据:

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

但是 update 使用这个:

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

将产生以下数据:

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

根据文档:https://firebase.google.com/docs/firestore/manage-data/add-data#update_fields_in_nested_objects

点表示法允许您在不覆盖其他嵌套字段的情况下更新单个嵌套字段。如果您更新没有点符号的嵌套字段,您将覆盖整个地图字段。

如上所述,这会替换整个朋友结构。

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

这不是。

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

还有一个有趣的行为可能有用但不明显。

当您进行 batch 更新时,不想检查您尝试更新的所有文档是否 存在

使用 batch update 如果至少有一个文档不存在,您的请求将失败。

使用 batch set {merge: true} 您的请求将成功更新所有现有文档并为不存在的 ID 创建虚拟文档。

可能的用例:将 google 分析合并到来自 analytics reporting api 的文档中,当此 api 同时提供现有文档和已删除文档的数据时.

进一步补充上述答案,如果您想要删除 地图中的嵌套字段,那么您可能想要使用updateset取决于您的用例。

如果您从以下内容开始并希望删除 "user1" 以外的所有配置文件条目,那么您有两个选择。

{
  "users": {
    "profiles": {
      "user1": ...,
      "user2": ...
    }
  }

更新

这将用提供的内容覆盖 profiles

update({
  'users.profiles': { 'user1': ... }
})

设置

这会将删除的内容合并到现有配置文件中, 保留未删除的内容

set({
  users: {
    profiles: {
      'user2': FieldValue.delete(),
      'user3': FieldValue.delete(),
      ...
    }
  }
}, { merge: true })

这仅适用于 Map,因为 setupdate 都会覆盖数组,除非您明确使用 array-specific operators such as arrayUnion.