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

如何在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] }
                                }
                              }
                            }
                          ]
                        }
                      ]
                    }
                  }
                }
              ]
            }
          }
        }
      }
    }
  ]
);

逻辑说明

  1. 遍历tasks数组:用$map逐个处理每个task对象
  2. 过滤目标用户:用$filter移除likes.users中匹配req.user._user的元素
  3. 计算移除数量:通过原users数组长度减去过滤后的数组长度,得到移除的数量x
  4. 更新计数字段:用原likes.likes数值减去x,得到更新后的计数
  5. 合并对象:用$mergeObjects将更新后的likes字段和原task的其他字段合并,重新组成tasks数组

注意事项

  • 确保MongoDB版本在4.2及以上,聚合管道更新是该版本新增的特性
  • 确认profileSchema中的user._user字段能和req.user._user正确匹配,避免过滤错误
  • 该操作是原子性的,整个更新过程在单条查询内完成,不会出现数据不一致的情况

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 12:50:01