使用MongoDB聚合根据数组字段存在性添加新数组字段
MongoDB聚合:仅为数组中存在指定字段的元素添加新字段
问题场景
现有collectionA中的文档结构如下:
{ "_id" : ObjectId("641893db137e63c5d6940f68"), "summaryId" : 20, "actions" : [ { "action" : "Action A", "actionDate" : "2023-02-25 20:59:49" }, { "action" : "Action B", "actionDate" : "2021-11-18 20:49:55", "actorRoleId" : 5 }, { "action" : "Action C", "actionDate" : "2021-11-25 20:49:55", "actorRoleId" : 4 }, { "action" : "Action D", "actionDate" : "2023-02-25 20:49:55" } ] }
需求是:仅为actions数组中包含actorRoleId字段的元素添加新字段actorUserId,使用聚合操作实现。
原代码存在问题:直接给整个actions数组的所有元素添加了actorUserId,不符合需求:
pipeline = [ { "$match": { "actions.actorRoleId": {"$exists": True} } }, { "$addFields": { "actions.actorUserId": "Testing" } }, { "$project": { "summaryId": True, "actions": True } }, {"$merge": "summary"}, ] db.collectionA.aggregate(pipeline)
正确解决方案
需要使用$map遍历数组元素,结合$cond条件判断和$mergeObjects合并字段,仅为符合条件的元素添加新字段:
pipeline = [ { "$match": { "actions.actorRoleId": {"$exists": True} } }, { "$addFields": { "actions": { "$map": { "input": "$actions", "as": "item", "in": { "$cond": { "if": {"$exists": ["$$item.actorRoleId", True]}, "then": {"$mergeObjects": ["$$item", {"actorUserId": "Testing"}]}, "else": "$$item" } } } } } }, { "$project": { "summaryId": True, "actions": True } }, {"$merge": "summary"} # 若要合并回原集合,可改为"collectionA" ] db.collectionA.aggregate(pipeline)
代码说明
- $match阶段:过滤出
actions数组中至少有一个元素包含actorRoleId的文档,避免处理无符合条件元素的文档,提升效率。 - $addFields阶段:
- 使用
$map遍历actions数组的每个元素(命名为$$item)。 - 通过
$cond判断当前元素是否存在actorRoleId字段:- 存在:用
$mergeObjects将原元素和新字段actorUserId合并,生成新的元素对象。 - 不存在:直接返回原元素,不做修改。
- 存在:用
- 使用
- $project阶段:保留需要的字段,可根据实际需求调整。
- $merge阶段:将聚合结果合并到指定集合,若要覆盖原文档,可添加
whenMatched: "replace"等参数(默认行为是合并字段)。
内容的提问来源于stack exchange,提问作者wheeliea
相关产品推荐
相关产品推荐

