MongoDB技术问题:如何用elemMatch作为更新字段的条件
MongoDB聚合管道:满足条件时向数组添加元素
问题背景
有如下结构的文档:
{ "profileSpherestatus": [ { "idf": "B002", "completedPercentage": 100 }, { "idf": "B003", "completedPercentage": 90 }, { "idf": "B004", "completedPercentage": 100 } ], "myGratificacions": [ { "idb": "B003", "gratification": 20 }, { "idb": "B004", "gratification": 30 } ] }
需要实现:当满足以下两个条件时,向myGratifications数组中添加指定对象:
profileSpherestatus数组中存在idf为"B002"且completedPercentage为100的元素myGratifications数组中不存在idb为"B002"的元素
待添加的对象:
newObject = { "idb":"B002", "gratification":10 }
尝试的管道及问题
尝试使用以下聚合管道,但报错$elemMatch无法在$set或$addFields中使用:
[ {"$set": { "myGratifications": {"$cond": { "if": { "$and": [ {"profileSpherestatus": {"$elemMatch": {"idf": "B002", "completedPercentage": 100}} }, {"$not": {"myGratifications":{"$elemMatch": {"idb": "B002"}}} } ] }, "then": { "$concatArrays": ["$myGratifications",[newObject]] }, "else": "$myGratifications" }} }} ]
解决方案
问题出在$elemMatch的使用方式上,在聚合表达式中需要调整语法,以下两种方案可解决:
方案1:用$expr包裹$elemMatch
$expr允许在聚合表达式中使用查询操作符,修正后的管道如下:
[ { "$set": { "myGratifications": { "$cond": { "if": { "$and": [ { "$expr": { "$elemMatch": ["$profileSpherestatus", {"idf": "B002", "completedPercentage": 100}] } }, { "$expr": { "$not": { "$elemMatch": ["$myGratificacions", {"idb": "B002"}] } } } ] }, "then": {"$concatArrays": ["$myGratificacions", [{"idb":"B002", "gratification":10}]]}, "else": "$myGratificacions" } } } } ]
方案2:用$anyElementTrue+$map替代$elemMatch
通过遍历数组生成布尔值集合,再判断是否存在符合条件的元素,语法更直观:
[ { "$set": { "myGratifications": { "$cond": { "if": { "$and": [ { "$anyElementTrue": { "$map": { "input": "$profileSpherestatus", "as": "item", "in": { "$and": [ {"$eq": ["$$item.idf", "B002"]}, {"$eq": ["$$item.completedPercentage", 100]} ] } } } }, { "$not": { "$anyElementTrue": { "$map": { "input": "$myGratificacions", "as": "item", "in": {"$eq": ["$$item.idb", "B002"]} } } } } ] }, "then": {"$concatArrays": ["$myGratificacions", [{"idb":"B002", "gratification":10}]]}, "else": "$myGratificacions" } } } } ]
说明
- 方案1通过
$expr解锁了$elemMatch在聚合表达式中的使用权限,修正原语法错误。 - 方案2完全避开
$elemMatch,用基础聚合操作实现相同逻辑,兼容性更强。
内容的提问来源于stack exchange,提问作者Juan
相关产品推荐
相关产品推荐

