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

MongoDB findOneAndUpdate:如何避免向数组插入重复对象?

解决MongoDB数组对象去重插入问题(按dateTime和title校验)

需求:MongoDB文档包含reports对象数组属性,向该数组添加新对象时,若数组中已存在dateTime和title均相同的对象,则不执行插入;若不存在,则插入新对象。

文档结构

{
    "_id" : ObjectId("637b99b36cc39a1fee0a4977"),
    "name" : "product1",
    "reports" : [
        {
            "_id" : ObjectId("63f60fe2029fcd31b93870d3"),
            "name" : "product1",
            "title" : "hi",
            "dateTime" : ISODate("2023-02-22T12:51:31.993+0000"),
            "createdAt" : ISODate("2023-02-22T12:51:46.351+0000")
        }
    ],
    ....
}

待添加的reports数据

const reports = {
  'xyz-xyz': [
    {
      name: 'xyz-xyz',
      title: 'good morning',
      dateTime: '2022-11-09T07:18:05.000Z',
      ...
    },
    {
      name: 'xyz-xyz',
      title: 'hi',
      dateTime: '2022-11-09T07:18:06.000Z',
      ...
    },
  ],
  xxx: [
    {
      name: 'xxx',
      title: 'hello',
      dateTime: '2022-11-09T07:19:05.000Z',
      ...
    },
  ]
}

错误尝试分析

  1. 第一段代码错误使用$inc做日期比较,且$in的写法无法在MongoDB查询上下文执行客户端数组map操作,语法完全无效。
  2. 第二段代码仅校验dateTime字段,未满足同时校验title的需求,且直接拼接整个待添加数组,未逐个对象判断重复。

正确实现方法

使用MongoDB聚合管道实现多字段重复判断,逐个处理待添加数组中的对象,判断现有reports数组是否存在dateTime和title均匹配的元素,不存在则追加。

for (let key in reports) {
  // 遍历当前key对应的所有待添加report对象
  for (const newReport of reports[key]) {
    // 将字符串日期转为MongoDB可识别的Date对象
    const targetDateTime = new Date(newReport.dateTime);
    const targetTitle = newReport.title;

    await Station.findOneAndUpdate(
      { "name": key },
      [
        {
          "$set": {
            "reports": {
              "$cond": [
                // 判断条件:reports数组中是否存在dateTime和title都匹配的元素
                {
                  "$anyElementTrue": {
                    "$map": {
                      "input": "$reports",
                      "as": "r",
                      "in": {
                        "$and": [
                          { "$eq": ["$$r.dateTime", targetDateTime] },
                          { "$eq": ["$$r.title", targetTitle] }
                        ]
                      }
                    }
                  }
                },
                // 存在重复则保持原数组
                "$reports",
                // 无重复则追加新对象
                { "$concatArrays": ["$reports", [newReport]] }
              ]
            }
          }
        }
      ],
      { new: true, upsert: true } // 可选:无对应文档时自动创建
    );
  }
}

关键说明

  • 用$anyElementTrue+$map遍历现有数组,精准判断多字段重复。
  • 必须将字符串日期转为Date对象,确保与MongoDB的ISODate类型一致,避免比较失效。
  • 双层循环逐个处理待添加对象,保证每个对象都能独立校验重复。
  • upsert: true为可选配置,可自动创建不存在的目标文档。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 20:57:29