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

如何在Mongoose中结合lastUpdated条件执行updateOne批量更新?

问题

使用Mongoose时需要实现以下文档更新逻辑:

  • 获取新批次matches数据后,按id匹配数据库中的文档
  • 仅当新文档的lastUpdated字段晚于数据库文档时才执行更新
  • 支持upsert新增不存在的文档
  • 不能将id和lastUpdated同时作为filter条件,否则会产生重复数据

尝试用bulkWrite结合arrayFilters实现时出现MongoBulkWriteError错误,以下是相关信息:

测试数据

数据库现有数据

const testMatchesOnDB = [
    { id: 1, team: "teamOneV1", lastUpdated: moment().subtract(10, "days") },
    {
      id: 2,
      team: "TeamTwoV1",
      lastUpdated: moment("2022-08-29T14:18:59+01:00"),
    },
    { id: 3, team: "TeamThreeV1", lastUpdated: moment().subtract(2, "days") },
];

新获取的API数据

const newMatchesFromAPI = [
    {
      id: 2,
      team: "TeamTwoV2",
      lastUpdated: moment("2022-08-29T14:18:59+01:00"),
    }, 
    { id: 3, team: "TeamThreeV2", lastUpdated: moment().subtract(1, "days") }, 
    { id: 4, team: "TeamFourV2", lastUpdated: moment() }, // 测试upsert
];

尝试的代码

await Test.bulkWrite(
    newMatchesFromAPI.map((match) => ({
      updateOne: {
        filter: {
          id: match.id,
        },
        update: match,
        upsert: true,
        arrayFilters: [{ lastUpdated: { $lt: moment(match.lastUpdated) } }],
      },
    }))
);

错误信息

MongoBulkWriteError: The array filter for identifier 'lastUpdated' was not used in the update { $setOnInsert: { id: 2 } }

期望的数据库结果

const desiredDB = [
  { id: 1, team: "teamOneV1", lastUpdated: moment().subtract(10, "days") }, // 未匹配,保持不变
  {
    id: 2,
    team: "TeamTwoV1",
    lastUpdated: moment("2022-08-29T14:18:59+01:00"), // 日期相等,不更新
  },
  { id: 3, team: "TeamThreeV2", lastUpdated: moment().subtract(1, "days") }, // 更新为较新数据
  { id: 4, team: "TeamFourV2", lastUpdated: moment() }, // upsert新增
];
正确实现方式

之前的错误原因是arrayFilters仅用于数组元素的条件更新,不适用于顶层字段的判断。要实现需求,需要结合$set和更新条件,同时利用upsert特性:

await Test.bulkWrite(
  newMatchesFromAPI.map((match) => ({
    updateOne: {
      filter: { id: match.id },
      update: {
        $set: {
          ...match,
          lastUpdated: match.lastUpdated.toDate() // 转换为MongoDB支持的Date类型
        }
      },
      upsert: true,
      // 设置更新条件:仅当数据库文档的lastUpdated更旧,或文档不存在时执行操作
      condition: {
        $or: [
          { lastUpdated: { $lt: match.lastUpdated.toDate() } },
          { lastUpdated: { $exists: false } }
        ]
      }
    }
  }))
);

逻辑说明

  1. 仅用id作为filter:确保按唯一标识匹配文档,避免重复数据
  2. $set批量更新字段:将新数据的所有字段同步到匹配文档中
  3. condition控制更新时机:
    • 当数据库存在文档时,仅在lastUpdated小于新数据时才执行更新
    • 当文档不存在时(upsert场景),lastUpdated不存在的条件成立,直接插入新文档
  4. 日期类型转换:用toDate()将moment对象转为MongoDB原生Date类型,避免类型不匹配问题

结果验证

  • id=1:未匹配新数据,保持原有状态
  • id=2:新数据与数据库的lastUpdated日期相等,不满足更新条件,保留原数据
  • id=3:新数据的lastUpdated更晚,执行字段更新
  • id=4:数据库中无匹配文档,自动upsert新增

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 10:42:24