You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firestore updateDoc单次请求更新两个数组失败问题排查

问题:Firestore单次updateDoc同时操作数组时,原数组无法移除元素

我在React中开发一个简单的任务应用,使用Firestore存储数据。需求是将任务标记为已完成时,从pending数组移除并添加到performed数组,反之亦然。最初两次调用updateDoc可正常实现功能,但改为单次调用updateDoc同时操作两个数组时,任务能添加到目标数组,却无法从原数组移除。

初始可行代码

const docRef = doc(db, 'users', uid)

const markDone = async task => {
  setIsReading(true)
  const { updateDoc, arrayUnion, arrayRemove } = await import('firebase/firestore')
  if (task.done === false) {
      await updateDoc(docRef, { 'listOfTask.pending': arrayRemove(task)})
      task.done = !task.done
      await updateDoc(docRef, { 'listOfTask.performed': arrayUnion(task)})
  } else {
      await updateDoc(docRef, { 'listOfTask.performed': arrayRemove(task) })
      task.done = !task.done
      await updateDoc(docRef, { 'listOfTask.pending': arrayUnion(task) })
  }
  await readData()
}

修改后的问题代码

const markDone = async task => {
  setIsReading(true)
  const { updateDoc, arrayUnion, arrayRemove } = await import('firebase/firestore')
  const t = task                 //Clone the task object
  if (task.done === false) {
    t.done = !t.done             //Change value to true in done property in cloned task
    await updateDoc(docRef, {
      'listOfTask.pending': arrayRemove(task), //Remove original task in pending
      'listOfTask.performed': arrayUnion(t)    //Add cloned task in performed 
    })
  } else {
    t.done = !t.done
    await updateDoc(docRef, {
      'listOfTask.pending': arrayUnion(task),
      'listOfTask.performed': arrayRemove(t)
    })
  }
  await readData()
}

数据结构:文档中listOfTask包含pending和performed两个数组,分别存储待办和已完成任务。


解决方案

问题根源在于对象引用和Firestore数组匹配规则:

  1. const t = task只是复制了对象引用,并非真正克隆,修改t.done时会同步改变原task对象的done值。
  2. Firestore的arrayRemove依赖完全匹配对象内容来移除元素,单次update中,原task的done值已经被修改,导致arrayRemove(task)无法匹配数组中原始的未修改元素,自然无法移除。

正确修改代码

需要真正克隆任务对象,确保原对象与克隆对象相互独立:

const docRef = doc(db, 'users', uid)

const markDone = async task => {
  setIsReading(true)
  const { updateDoc, arrayUnion, arrayRemove } = await import('firebase/firestore')
  // 浅克隆对象(无嵌套结构时适用),嵌套结构改用JSON.parse(JSON.stringify(task))深克隆
  const t = { ...task }
  if (task.done === false) {
    t.done = !t.done
    await updateDoc(docRef, {
      'listOfTask.pending': arrayRemove(task), // 原task未被修改,匹配pending数组中的原始元素
      'listOfTask.performed': arrayUnion(t)    // 克隆对象t已修改done值,添加到performed
    })
  } else {
    t.done = !t.done
    await updateDoc(docRef, {
      'listOfTask.pending': arrayUnion(t),     // 克隆对象t已修改done值,添加到pending
      'listOfTask.performed': arrayRemove(task) // 原task未被修改,匹配performed数组中的原始元素
    })
  }
  await readData()
}

这样修改后,原task对象的属性保持不变,arrayRemove能精准匹配数组中的原始元素,单次update即可同时完成移除和添加操作。


内容的提问来源于stack exchange,提问作者user20294238

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 10:43:29