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

Node.js中MongoDB嵌套对象数组条件更新实现

MongoDB嵌套数组更新:存在日期则增量计数,不存在则新增条目

问题背景

使用Node.js操作MongoDB,需要对存储带日期戳的嵌套对象数组执行更新,现有集合文档结构如下:

{
  _id: 629f2f5e7aa147d6503957d0,
  kid_id: "629f2f5e7aa147d6503957ce",
  inventory: [
    { 
      size: "0", 
      purchased: "0", 
      used: [{}], 
      _id: "111111"
    },
    { 
      size: "1", 
      purchased: "10", 
      used: [
        { date: "06/08/22", count: "2"}
      ], 
      _id: "222222"
    }
  ]
}

需求说明

  • 基础需求:定位到inventory数组中size值为1的条目,向其内部的used数组追加{ date: "06/09/22", count: "4"}对象
  • 长期逻辑:
    • 若used数组中已存在相同date值的条目,直接对该条目的count值做增量更新
    • 若传入的date值在used数组中不存在,则新增对应的日期统计对象

原有问题代码

最初编写的代码存在两处核心错误:一是没有处理used二级数组的匹配逻辑,二是没有兼容「存在则更新、不存在则新增」的数组操作逻辑,无法满足需求:

router.put('/used', auth, async (req, res) => {
  let kidID = req.body.kid_id;
  let size = req.body.size;

  try {
    const record = await InventoryRecord.updateOne(
      { kid_id: kidID },
      { $inc: { 'inventory.$[el].used': -1 } },
      { arrayFilters: [{ 'el.size': size }] }
    );
    console.log(record);
    res.send(record);
  } catch (error) {
    res.send({ message: error.message });
  }
});

可行实现方案

MongoDB 4.2及以上版本支持聚合管道更新,可以通过$cond结合数组操作单次请求完成需求,无需多次查询,实现代码如下:

router.put('/used', auth, async (req, res) => {
  const { kid_id: kidID, size, updateDate, addCount } = req.body;
  // 入参示例:kidID为对应文档关联id,size="1",updateDate="06/09/22",addCount=4
  try {
    const record = await InventoryRecord.updateOne(
      { kid_id: kidID },
      [
        {
          $set: {
            inventory: {
              $map: {
                input: "$inventory",
                in: {
                  $cond: [
                    { $eq: ["$$this.size", size] },
                    // 匹配到对应size的inventory条目
                    {
                      $mergeObjects: [
                        "$$this",
                        {
                          used: {
                            $cond: [
                              // 校验used数组中是否已存在对应日期条目
                              { $in: [updateDate, "$$this.used.date"] },
                              // 日期存在:遍历used数组给对应条目的count做增量
                              {
                                $map: {
                                  input: "$$this.used",
                                  in: {
                                    $cond: [
                                      { $eq: ["$$this.date", updateDate] },
                                      {
                                        $mergeObjects: [
                                          "$$this",
                                          // 示例中count存为字符串,此处做类型转换,若存储为Number类型可去掉$toInt
                                          { count: { $add: [{ $toInt: "$$this.count" }, addCount] } }
                                        ]
                                      },
                                      "$$this"
                                    ]
                                  }
                                }
                              },
                              // 日期不存在:拼接新的日期统计对象到used数组末尾
                              { $concatArrays: ["$$this.used", [{ date: updateDate, count: String(addCount) }]] }
                            ]
                          }
                        }
                      ]
                    },
                    // 不匹配size的inventory条目原样保留
                    "$$this"
                  ]
                }
              }
            }
          }
        }
      ]
    );
    console.log(record);
    res.send(record);
  } catch (error) {
    res.send({ message: error.message });
  }
});

优化建议

  • 建议将文档中purchased、count这类数值字段从字符串类型改为Number类型,避免每次更新做类型转换,减少性能损耗和类型异常
  • 如果使用的MongoDB版本低于4.2不支持聚合更新,可以分两步实现:先查询对应文档判断目标日期是否存在,再根据结果执行$inc增量或$push追加操作,逻辑更直观但会多一次数据库查询

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 13:21:30