MongoDB如何通过ID数组汇总司机积分并更新玩家总积分?
问题解决思路与修正代码
你的聚合查询结果始终为0,核心原因是引用了不存在的字段,且未正确处理$lookup返回的结果数组,下面一步步修正:
1. 原查询的错误点
$lookup执行后,匹配到的司机数据会存在result数组字段里,你直接用$sum: "$points",但文档中根本没有points这个字段,求和自然为0- 每个
driver_selection对应的result是长度为1的数组(司机ID唯一),需要先取出数组内的driver_points值才能求和
2. 修正后的聚合查询(先正确计算玩家总积分)
db.players.aggregate([ // 展开司机选择数组 { $unwind: "$driver_selection" }, // 关联司机集合,匹配对应ID的司机数据 { $lookup: { from: "drivers", localField: "driver_selection", foreignField: "id", as: "driver_data" } }, // 展开关联得到的driver_data数组(每个匹配唯一,展开后得到单条司机文档) { $unwind: "$driver_data" }, // 按玩家ID分组,汇总司机积分 { $group: { _id: "$id", player_name: { $first: "$player_name" }, // 保留玩家名称 total_points: { $sum: "$driver_data.driver_points" } // 正确引用司机积分字段 } } ])
执行后会得到正确的玩家积分结果,比如Tom的结果为{ _id: 1, player_name: "Tom", total_points: 450 }
3. 直接更新玩家集合的total_points字段
如果要把计算结果写回players集合,可在聚合末尾添加$merge阶段自动更新匹配文档:
db.players.aggregate([ { $unwind: "$driver_selection" }, { $lookup: { from: "drivers", localField: "driver_selection", foreignField: "id", as: "driver_data" } }, { $unwind: "$driver_data" }, { $group: { _id: "$id", player_name: { $first: "$player_name" }, total_points: { $sum: "$driver_data.driver_points" } } }, // 合并回players集合,按ID匹配并更新积分 { $merge: { into: "players", on: "_id", whenMatched: [ { $set: { total_points: "$total_points" } } ], whenNotMatched: "discard" // 忽略不存在的玩家 } } ])
4. 更简洁的更新方案(无需unwind)
MongoDB 3.6+支持在更新管道中使用聚合操作,可直接对嵌套数组字段求和,省去$unwind和$group步骤:
db.players.updateMany( {}, // 匹配所有玩家 [ { $lookup: { from: "drivers", localField: "driver_selection", foreignField: "id", as: "selected_drivers" } }, { $set: { total_points: { $sum: "$selected_drivers.driver_points" // 直接对数组内的积分求和 } } } ] )
内容的提问来源于stack exchange,提问作者Mark McNaughton
相关产品推荐
相关产品推荐

