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

MongoDB中$addToSet更新数组并同步$size更新长度失败及$inc疑问

MongoDB更新数组去重并同步长度,以及管道中使用$inc的方法

问题背景

定义的Mongoose Schema如下:

const appJobSchema = new mongoose.Schema({
    data: [
      { type: Schema.Types.Mixed }
    ],
    stat: {
      dataCount: { type: Number, default: 0 },
    }
})

需求是:向data数组中批量添加记录(自动去重),同时将stat.dataCount同步更新为数组的最新长度。

最初的错误尝试

最初编写的更新代码:

export async function updateDataById(id: string, records: any[]) {
  return await model.updateOne({ '_id': id }, {  
    '$addToSet': { 'data': { '$each': records } } ,  
    '$set': { 
      'stat.dataCount': { $size: "$data" }  
    } 
  });
}

运行后报错:

UncaughtException: Cast to Number failed for value "{ '$size': '$data' }" (type Object) at path "stat.dataCount"

原因是:传统更新操作(非管道模式)中,$set不能直接使用聚合表达式(比如$size),只能赋值常量或引用文档外的值。

中间尝试的方案

  • 使用$concatArrays拼接数组:能同步更新长度,但无法实现去重,不符合需求;
  • 在更新管道中直接使用$addToSet/$inc:报错

UncaughtException: Invalid update pipeline operator: "$addToSet".

因为更新管道只能使用聚合阶段操作符(比如$set、$project等),不能直接用传统的更新操作符($addToSet、$inc属于此类)。

已实现的可行方案

通过$setUnion在更新管道中实现去重更新,并同步数组长度:

await Model.updateOne({'_id':id},
  [   
    {
      "$set": {
        "data": {
          $setUnion: [ "$data",  records  ]
        }
      }
    },
    { 
      '$set': { 
        'stat.dataCount': { $size: "$data" }  
      }  
    },
  ]);

疑问解答:如何在更新管道中使用类似$inc的递增操作

更新管道中无法直接使用$inc操作符,需要通过聚合表达式模拟递增逻辑。核心思路是先计算出增量值,再用$add将原字段值与增量相加。

实现代码示例

如果需要针对stat.dataCount实现类似$inc的效果(比如只增加本次新增的元素数量),可以这样写:

await Model.updateOne({'_id': id}, [
  {
    "$set": {
      // 计算本次新增的元素(原数组中不存在的记录)
      "tempAddedElements": { $setDifference: [records, "$data"] },
      // 更新data为去重后的完整数组
      "data": { $setUnion: ["$data", records] }
    }
  },
  {
    "$set": {
      // 用$add实现递增:原count + 新增元素的数量
      "stat.dataCount": { $add: ["$stat.dataCount", { $size: "$tempAddedElements" }] },
      // 清理临时字段
      "tempAddedElements": "$$REMOVE"
    }
  }
]);

逻辑说明

  1. 用$setDifference计算出本次要添加的记录中,原数组没有的元素,得到临时数组tempAddedElements;
  2. 用$size获取临时数组的长度,也就是本次新增的元素数量;
  3. 用$add将stat.dataCount的原值与新增数量相加,实现类似$inc的递增效果;
  4. 最后用$$REMOVE删除临时字段,避免污染文档结构。

如果只是需要同步数组的最新长度,直接使用$size: "$data"会更简单,无需计算增量。但如果业务场景需要基于增量更新,上述方法就可以满足需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 14:47:15