如何在Mongoose同查询中从数组移除x个对象并更新另一字段
问题:MongoDB/Mongoose中同一条查询里用$pull移除的数量更新对应字段
需求:希望在同一条Mongoose查询中,从数组中移除x个对象,并使用该x值更新同一文档中的另一个字段。
相关Schema定义
export const publicTaskSchema = new Schema({ likes: { likes: { required: false, type: Number, default: 0 }, users: { required: false, type: [profileSchema], default: [] }, }, }) export const publicTaskListSchema = new Schema({ tasks: { required: true, type: [publicTaskSchema], default: null }, });
尝试的查询代码
const PublicTaskList = model("publicTaskList"); await PublicTaskList.updateMany( {}, { // 若此处移除了2个对象 $pull: { "tasks.$[].likes.users": { "user._user": req.user?._user, }, }, // 需将如下字段递减2 $inc: { tasks.$[].likes.likes: /* 此处填入上述移除的数量 */ } } );
核心问题:如何获取$pull操作移除的对象数量x,并在同一条查询中用该值对likes.likes字段进行对应递减操作?
解决方案
MongoDB常规的updateMany操作无法直接让$pull和$inc产生依赖——这两个操作是并行执行的,没办法直接获取$pull移除的数量给$inc使用。要实现同一条查询内完成需求,需要用聚合管道式更新(MongoDB 4.2及以上版本支持),通过聚合逻辑计算移除数量并同步更新字段。
具体实现代码
const PublicTaskList = model("publicTaskList"); await PublicTaskList.updateMany( {}, [ { $set: { tasks: { $map: { input: "$tasks", as: "task", in: { $mergeObjects: [ "$$task", { likes: { // 过滤掉要移除的用户 users: { $filter: { input: "$$task.likes.users", as: "user", cond: { $ne: ["$$user.user._user", req.user?._user] } } }, // 计算移除数量并更新likes计数 likes: { $subtract: [ "$$task.likes.likes", { $subtract: [ { $size: "$$task.likes.users" }, { $size: { $filter: { input: "$$task.likes.users", as: "user", cond: { $ne: ["$$user.user._user", req.user?._user] } } } } ] } ] } } } ] } } } } } ] );
逻辑说明
- 遍历tasks数组:用
$map逐个处理每个task对象 - 过滤目标用户:用
$filter移除likes.users中匹配req.user._user的元素 - 计算移除数量:通过原users数组长度减去过滤后的数组长度,得到移除的数量x
- 更新计数字段:用原
likes.likes数值减去x,得到更新后的计数 - 合并对象:用
$mergeObjects将更新后的likes字段和原task的其他字段合并,重新组成tasks数组
注意事项
- 确保MongoDB版本在4.2及以上,聚合管道更新是该版本新增的特性
- 确认
profileSchema中的user._user字段能和req.user._user正确匹配,避免过滤错误 - 该操作是原子性的,整个更新过程在单条查询内完成,不会出现数据不一致的情况
内容的提问来源于stack exchange,提问作者userWantsToCode
相关产品推荐
相关产品推荐

