更新文档 #

一、Update概述 #

1.1 Update vs Replace #

text
Update特点:
├── 部分更新(合并)
├── 保留未修改的字段
├── 只更新指定字段
└── 适合增量更新

Replace特点:
├── 完全替换data
├── 删除未指定的字段
├── 整体替换
└── 适合全量更新

1.2 基本语法 #

javascript
// Update语法
Update(ref, {
  data: { ... }
})

// Replace语法
Replace(ref, {
  data: { ... }
})

二、Update更新 #

2.1 基本更新 #

javascript
// 更新单个字段
Update(Ref(Collection("users"), "123456"), {
  data: {
    age: 31
  }
})

// 更新多个字段
Update(Ref(Collection("users"), "123456"), {
  data: {
    name: "Tom Updated",
    age: 31,
    updatedAt: Now()
  }
})

2.2 合并更新 #

javascript
// Update会合并数据
// 原文档: { name: "Tom", email: "tom@example.com", age: 30 }
Update(Ref(Collection("users"), "123456"), {
  data: { age: 31 }
})
// 结果: { name: "Tom", email: "tom@example.com", age: 31 }

2.3 嵌套更新 #

javascript
// 更新嵌套对象
Update(Ref(Collection("users"), "123456"), {
  data: {
    address: {
      city: "Shanghai"
    }
  }
})
// 注意:这会替换整个address对象

// 正确的嵌套更新方式
Let(
  {
    doc: Get(Ref(Collection("users"), "123456")),
    oldAddress: Select(["data", "address"], Var("doc"))
  },
  Update(Ref(Collection("users"), "123456"), {
    data: {
      address: Merge(
        Var("oldAddress"),
        { city: "Shanghai" }
      )
    }
  })
)

2.4 数组更新 #

javascript
// 添加数组元素
Let(
  {
    doc: Get(Ref(Collection("users"), "123456")),
    oldTags: Select(["data", "tags"], Var("doc"), [])
  },
  Update(Ref(Collection("users"), "123456"), {
    data: {
      tags: Append(["new_tag"], Var("oldTags"))
    }
  })
)

// 移除数组元素
Let(
  {
    doc: Get(Ref(Collection("users"), "123456")),
    oldTags: Select(["data", "tags"], Var("doc"), [])
  },
  Update(Ref(Collection("users"), "123456"), {
    data: {
      tags: Filter(
        Var("oldTags"),
        Lambda("tag", Not(Equals(Var("tag"), "remove_tag")))
      )
    }
  })
)

三、Replace替换 #

3.1 基本替换 #

javascript
// 完全替换data
Replace(Ref(Collection("users"), "123456"), {
  data: {
    name: "Tom Replaced",
    email: "tom.new@example.com"
  }
})
// 原有其他字段会被删除

3.2 Replace vs Update #

javascript
// 原文档
{
  data: {
    name: "Tom",
    email: "tom@example.com",
    age: 30,
    address: { city: "Beijing" }
  }
}

// Update结果
Update(ref, { data: { age: 31 } })
// {
//   data: {
//     name: "Tom",
//     email: "tom@example.com",
//     age: 31,              // 更新
//     address: { city: "Beijing" }  // 保留
//   }
// }

// Replace结果
Replace(ref, { data: { age: 31 } })
// {
//   data: {
//     age: 31              // 只有age
//   }
// }

四、条件更新 #

4.1 检查后更新 #

javascript
// 检查文档存在后更新
Let(
  {
    ref: Ref(Collection("users"), "123456")
  },
  If(
    Exists(Var("ref")),
    Update(Var("ref"), {
      data: { updatedAt: Now() }
    }),
    Abort("Document not found")
  )
)

4.2 值验证更新 #

javascript
// 验证值后更新
Let(
  {
    ref: Ref(Collection("products"), "prod_001"),
    newPrice: 99.99
  },
  If(
    And(
      IsNumber(Var("newPrice")),
      GT(Var("newPrice"), 0)
    ),
    Update(Var("ref"), {
      data: {
        price: Var("newPrice"),
        updatedAt: Now()
      }
    }),
    Abort("Invalid price")
  )
)

4.3 状态验证更新 #

javascript
// 验证状态后更新
Let(
  {
    ref: Ref(Collection("orders"), "order_001"),
    doc: Get(Var("ref")),
    currentStatus: Select(["data", "status"], Var("doc"))
  },
  If(
    Equals(Var("currentStatus"), "pending"),
    Update(Var("ref"), {
      data: {
        status: "processing",
        updatedAt: Now()
      }
    }),
    Abort("Order is not in pending status")
  )
)

五、原子更新 #

5.1 计数器更新 #

javascript
// 原子计数器
Let(
  {
    ref: Ref(Collection("counters"), "visits")
  },
  Update(Var("ref"), {
    data: {
      count: Add(
        Select(["data", "count"], Get(Var("ref"))),
        1
      )
    }
  })
)

5.2 乐观锁更新 #

javascript
// 使用时间戳进行乐观锁
Let(
  {
    ref: Ref(Collection("users"), "123456"),
    doc: Get(Var("ref")),
    currentTs: Select(["ts"], Var("doc")),
    expectedTs: Var("clientTs")
  },
  If(
    Equals(Var("currentTs"), Var("expectedTs")),
    Update(Var("ref"), {
      data: { name: "Updated Name" }
    }),
    Abort("Document was modified by another transaction")
  )
)

5.3 库存更新 #

javascript
// 原子库存更新
Let(
  {
    ref: Ref(Collection("products"), "prod_001"),
    doc: Get(Var("ref")),
    currentStock: Select(["data", "stock"], Var("doc")),
    quantity: 5
  },
  If(
    GTE(Var("currentStock"), Var("quantity")),
    Update(Var("ref"), {
      data: {
        stock: Subtract(Var("currentStock"), Var("quantity")),
        updatedAt: Now()
      }
    }),
    Abort("Insufficient stock")
  )
)

六、批量更新 #

6.1 Map批量更新 #

javascript
// 批量更新多个文档
Map(
  [
    { id: "1", name: "User 1" },
    { id: "2", name: "User 2" },
    { id: "3", name: "User 3" }
  ],
  Lambda("item",
    Update(
      Ref(Collection("users"), Select("id", Var("item"))),
      { data: { name: Select("name", Var("item")) } }
    )
  )
)

6.2 条件批量更新 #

javascript
// 批量更新符合条件的文档
Foreach(
  Paginate(Match(Index("users_by_status"), "inactive")),
  Lambda("ref",
    Update(Var("ref"), {
      data: {
        status: "archived",
        archivedAt: Now()
      }
    })
  )
)

6.3 分页批量更新 #

javascript
// 分页批量更新(处理大量数据)
Let(
  {
    page: Paginate(
      Match(Index("users_by_status"), "pending"),
      { size: 100 }
    )
  },
  Foreach(
    Var("page"),
    Lambda("ref",
      Update(Var("ref"), {
        data: {
          status: "active",
          activatedAt: Now()
        }
      })
    )
  )
)

七、字段操作 #

7.1 添加字段 #

javascript
// 添加新字段
Update(Ref(Collection("users"), "123456"), {
  data: {
    nickname: "Tommy",
    verified: true
  }
})

7.2 删除字段 #

javascript
// 删除字段(设为null)
Update(Ref(Collection("users"), "123456"), {
  data: {
    tempField: null
  }
})

// 完全删除字段
Let(
  {
    doc: Get(Ref(Collection("users"), "123456")),
    data: Select(["data"], Var("doc"))
  },
  Replace(Ref(Collection("users"), "123456"), {
    data: Merge(
      Var("data"),
      { tempField: null }
    )
  })
)

7.3 重命名字段 #

javascript
// 重命名字段
Let(
  {
    doc: Get(Ref(Collection("users"), "123456")),
    oldName: Select(["data", "oldField"], Var("doc"))
  },
  Update(Ref(Collection("users"), "123456"), {
    data: {
      newField: Var("oldName"),
      oldField: null
    }
  })
)

八、引用更新 #

8.1 更新引用字段 #

javascript
// 更新单个引用
Update(Ref(Collection("orders"), "order_001"), {
  data: {
    user: Ref(Collection("users"), "user_002")
  }
})

// 更新引用数组
Let(
  {
    doc: Get(Ref(Collection("orders"), "order_001")),
    oldProducts: Select(["data", "products"], Var("doc"), [])
  },
  Update(Ref(Collection("orders"), "order_001"), {
    data: {
      products: Append(
        Ref(Collection("products"), "prod_003"),
        Var("oldProducts")
      )
    }
  })
)

8.2 级联更新 #

javascript
// 更新用户时更新相关订单
Let(
  {
    userRef: Ref(Collection("users"), "user_001"),
    newName: "Tom Updated"
  },
  Do(
    // 更新用户
    Update(Var("userRef"), {
      data: { name: Var("newName") }
    }),
    // 更新相关订单中的用户名缓存
    Foreach(
      Paginate(Match(Index("orders_by_user"), Var("userRef"))),
      Lambda("orderRef",
        Update(Var("orderRef"), {
          data: { userName: Var("newName") }
        })
      )
    )
  )
)

九、实际应用示例 #

9.1 用户资料更新 #

javascript
// 完整的用户资料更新
Let(
  {
    userRef: Ref(Collection("users"), "user_001"),
    updates: {
      name: "Tom Updated",
      phone: "+86-138-xxxx-xxxx",
      bio: "Software Engineer"
    }
  },
  If(
    Exists(Var("userRef")),
    Update(Var("userRef"), {
      data: Merge(
        Var("updates"),
        { updatedAt: Now() }
      )
    }),
    Abort("User not found")
  )
)

9.2 订单状态更新 #

javascript
// 订单状态流转
Let(
  {
    orderRef: Ref(Collection("orders"), "order_001"),
    newStatus: "shipped",
    trackingNumber: "TRACK123456"
  },
  Let(
    {
      doc: Get(Var("orderRef")),
      currentStatus: Select(["data", "status"], Var("doc"))
    },
    If(
      And(
        Equals(Var("currentStatus"), "processing"),
        Or(
          Equals(Var("newStatus"), "shipped"),
          Equals(Var("newStatus"), "cancelled")
        )
      ),
      Do(
        Update(Var("orderRef"), {
          data: {
            status: Var("newStatus"),
            trackingNumber: Var("trackingNumber"),
            shippedAt: Now(),
            updatedAt: Now()
          }
        }),
        // 创建状态变更记录
        Create(Collection("order_history"), {
          data: {
            order: Var("orderRef"),
            fromStatus: Var("currentStatus"),
            toStatus: Var("newStatus"),
            timestamp: Now()
          }
        })
      ),
      Abort("Invalid status transition")
    )
  )
)

9.3 产品库存更新 #

javascript
// 产品库存更新
Let(
  {
    productRef: Ref(Collection("products"), "prod_001"),
    quantity: -5  // 负数表示减少库存
  },
  Let(
    {
      doc: Get(Var("productRef")),
      currentStock: Select(["data", "stock"], Var("doc")),
      newStock: Add(Var("currentStock"), Var("quantity"))
    },
    If(
      GTE(Var("newStock"), 0),
      Update(Var("productRef"), {
        data: {
          stock: Var("newStock"),
          updatedAt: Now()
        }
      }),
      Abort("Insufficient stock")
    )
  )
)

十、更新最佳实践 #

10.1 始终更新时间戳 #

javascript
// 好的做法
Update(ref, {
  data: {
    name: "New Name",
    updatedAt: Now()
  }
})

10.2 验证更新 #

javascript
// 验证后再更新
Let(
  {
    ref: Ref(Collection("users"), "123456"),
    newEmail: "new@example.com"
  },
  If(
    Regex(Var("newEmail"), "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"),
    If(
      Not(Exists(Match(Index("users_by_email"), Var("newEmail")))),
      Update(Var("ref"), {
        data: { email: Var("newEmail"), updatedAt: Now() }
      }),
      Abort("Email already in use")
    ),
    Abort("Invalid email format")
  )
)

10.3 返回更新后的文档 #

javascript
// 返回更新后的完整文档
Let(
  {
    updated: Update(Ref(Collection("users"), "123456"), {
      data: { name: "Updated Name" }
    })
  },
  {
    id: Select(["ref", "id"], Var("updated")),
    name: Select(["data", "name"], Var("updated")),
    updatedAt: Select(["data", "updatedAt"], Var("updated"))
  }
)

十一、总结 #

更新文档要点:

操作 说明
Update 部分更新(合并)
Replace 完全替换
Merge 合并对象
Append 添加数组元素
Filter 过滤数组元素

下一步,让我们学习删除文档!

最后更新:2026-03-27