MongoDB聚合查询:按书籍作者统计文档数量的问题排查
MongoDB聚合统计指定作者书籍数量
集合数据
bookSchema集合中的数据如下:
[ { _id: ObjectId("637d05dc32428ed75ea08d09"), book_details: { book_name: "random123", book_auth: "Amber" } }, { _id: ObjectId("637d0673ce0f17f6c473dee2"), book_details: { book_name: "random321", book_auth: "Amber" } }, { _id: ObjectId("637d069a3d597c8458ebe4ec"), book_details: { book_name: "random676", book_auth: "Amber" } }, { _id: ObjectId("637d06c05b32d503007bcb54"), book_details: { book_name: "random999", book_auth: "Saurav" } } ]
期望输出
需要得到如下格式的统计结果:
{ score_ambr: 3, score_saurabh: 1 }
尝试的错误查询及问题
使用以下聚合语句时,结果不符合预期:
db.bookSchema.aggregate([ { "$group": { "_id": { "$eq": [ "$book_details.book_auth", "Amber" ] }, "score_ambr": { "$sum": 1 } }, }, { "$group": { "_id": { "$eq": [ "$book_details.book_auth", "Saurav" ] }, "score_saurabh": { "$sum": 1 } }, } ])
错误原因:
- 连续的
$group阶段会丢弃前一阶段的非_id字段,第二个$group无法访问原始的book_details.book_auth字段,导致分组逻辑失效。 - 分组依据使用
$eq返回布尔值,无法精准区分目标作者,统计逻辑错误。
正确实现方法
方法一:单分组阶段条件统计(推荐)
直接在一次$group中通过$cond条件判断,分别累加指定作者的书籍数量:
db.bookSchema.aggregate([ { "$group": { "_id": null, "score_ambr": { "$sum": { "$cond": [{ "$eq": ["$book_details.book_auth", "Amber"] }, 1, 0] } }, "score_saurabh": { "$sum": { "$cond": [{ "$eq": ["$book_details.book_auth", "Saurav"] }, 1, 0] } } } }, { "$project": { "_id": 0 } } ])
逻辑说明:
$group按null分组,将所有文档聚合为一组。- 每个
$sum中用$cond判断作者是否匹配,匹配则加1,否则加0,最终得到对应作者的书籍总数。 $project移除多余的_id字段,得到期望格式。
方法二:分组后转键值对
先按作者分组统计数量,再将结果转换为指定键名的对象:
db.bookSchema.aggregate([ // 按作者分组统计数量 { "$group": { "_id": "$book_details.book_auth", "count": { "$sum": 1 } } }, // 将分组结果转为键值对数组 { "$group": { "_id": null, "scores": { "$push": { "k": { "$cond": { if: { "$eq": ["$_id", "Amber"] }, then: "score_ambr", else: "score_saurabh" } }, "v": "$count" } } } }, // 将键值对数组转为对象并作为根文档 { "$replaceRoot": { "newRoot": { "$arrayToObject": "$scores" } } } ])
逻辑说明:
- 第一个
$group统计每个作者的书籍数量。 - 第二个
$group将所有分组结果聚合,用$push生成包含指定键名(k)和数量(v)的数组。 $replaceRoot结合$arrayToObject将键值对数组转换为目标格式的对象。
内容的提问来源于stack exchange,提问作者Sushant Rad
相关产品推荐
相关产品推荐

