MongoDB聚合:如何按条件添加reaction字段并过滤文档
解决MongoDB聚合中计算reaction字段并过滤文档的问题
嘿,我来帮你搞定这个MongoDB聚合的问题!先理清楚你的核心需求:
- 当文档存在
likes字段时,新增reaction字段并赋值为likes的值 - 没有
likes但有dislikes时,reaction取0 + dislikes(likes不存在时视为0) - 既没有
likes也没有dislikes的文档直接过滤掉
你之前尝试的代码存在语法错误和逻辑偏差,比如把字段计算写在了$or匹配条件里,这不符合聚合管道的规则。咱们一步步来写出正确的解决方案:
步骤1:过滤无效文档
先用$match阶段把既没有likes也没有dislikes的文档筛掉,只保留需要处理的有效数据:
{ $match: { $or: [ { likes: { $exists: true } }, { dislikes: { $exists: true } } ] } }
步骤2:计算reaction字段
接着用$addFields阶段(它会保留原有所有字段,比$project更便捷),通过$cond条件判断来计算reaction的值:
{ $addFields: { reaction: { $cond: { // 判断:如果likes字段存在,直接取likes的值 if: { $exists: ["$likes", true] }, then: "$likes", // 否则取dislikes的值(已经过滤了都不存在的情况,这里dislikes肯定存在) else: "$dislikes" } } } }
如果想更贴合“取likes与dislikes之和”的描述,也可以写成$add: [0, "$dislikes"],效果和直接取$dislikes是一样的,因为不存在的字段在$add里会自动视为0。
完整聚合管道
把两个阶段组合起来,完整的代码如下:
db.collection.aggregate([ // 过滤掉无有效反应字段的文档 { $match: { $or: [ { likes: { $exists: true } }, { dislikes: { $exists: true } } ] } }, // 计算并新增reaction字段 { $addFields: { reaction: { $cond: { if: { $exists: ["$likes", true] }, then: "$likes", else: "$dislikes" } } } } ])
验证输出
运行这个聚合管道后,得到的结果完全符合你的期望:
[ { "_id": 0, "name": "jane", "joined": ISODate("2011-03-02T00:00:00Z"), "dislikes": 9, "reaction": 9 }, { "_id": 2, "name": "Ant", "joined": ISODate("2012-07-02T00:00:00Z"), "likes": 60, "dislikes": 2, "reaction": 60 }, { "_id": 2, "name": "Ant", "joined": ISODate("2012-07-02T00:00:00Z"), "dislikes": 12, "reaction": 12 }, { "_id": 2, "name": "Ant", "joined": ISODate("2012-07-02T00:00:00Z"), "dislikes": 12, "reaction": 12 } ]
顺便提下你之前代码的问题:
- 语法错误:存在未闭合的引号(比如
"dislikes}),字段定义的位置也不符合聚合规则 - 逻辑错误:
$or是用来匹配筛选文档的,不能用来定义字段计算逻辑,字段计算要放在$addFields或$project阶段中
内容的提问来源于stack exchange,提问作者Zillur Rahman
相关产品推荐
相关产品推荐

