如何在MongoDB中统计特定建筑师设计的已完工房屋数量
解决MongoDB跨集合统计指定建筑师完成房屋数量的问题
需求说明:统计指定建筑师(如Smith Stone)设计的、状态为completed的房屋数量,两个集合的关联关系为houses.plansId(字符串类型)对应plans._id(ObjectId类型)。
原查询的错误点
- 在
$lookup的pipeline中,引用外部集合(houses)的字段时,不能直接写houses.plansId,需要通过let定义变量并使用$$变量名的方式引用 - 匹配
arquitec字段不需要嵌套在$expr中,直接作为普通条件即可 - 缺少最终的统计步骤,没有对符合条件的文档进行计数
- 字段引用错误,
{ "$toString": "$plans._id" }应改为{ "$toString": "$_id" }(pipeline内针对plans集合文档,直接用$_id指代当前文档的_id)
正确查询方案
方案一:从houses集合出发聚合
先筛选已完成的房屋,再关联匹配目标建筑师的方案,最后统计数量:
db.houses.aggregate([ // 第一步:筛选状态为completed的房屋,减少后续处理数据量 { "$match": { "status": "completed" } }, // 第二步:关联plans集合,匹配对应建筑师的方案 { "$lookup": { "from": "plans", "let": { "housePlansId": "$plansId" }, // 定义变量存储当前房屋的plansId "pipeline": [ { "$match": { "$expr": { "$eq": [ { "$toString": "$_id" }, "$$housePlansId" ] }, // 匹配_id转字符串后等于房屋的plansId "arquitec": "Smith Stone" // 直接匹配目标建筑师 } } ], "as": "matchedPlans" // 关联结果的存储字段名 } }, // 第三步:过滤出确实关联到目标建筑师方案的房屋 { "$match": { "matchedPlans": { "$ne": [] } } }, // 第四步:统计符合条件的房屋总数 { "$count": "completedHouseCount" } ])
方案二:从plans集合出发聚合(更高效)
先筛选目标建筑师的方案,再关联对应已完成的房屋,最后统计总数,适合建筑师对应的方案数量较少的场景:
db.plans.aggregate([ // 第一步:筛选出Smith Stone设计的所有方案 { "$match": { "arquitec": "Smith Stone" } }, // 第二步:关联houses集合,匹配状态为completed且plansId匹配的房屋 { "$lookup": { "from": "houses", "let": { "planIdStr": { "$toString": "$_id" } }, // 将ObjectId转为字符串,匹配houses的plansId "pipeline": [ { "$match": { "$expr": { "$eq": [ "$plansId", "$$planIdStr" ] }, "status": "completed" } } ], "as": "completedHouses" } }, // 第三步:统计所有关联到的已完成房屋总数 { "$group": { "_id": null, "total": { "$sum": { "$size": "$completedHouses" } } } }, // 第四步:重命名字段,让结果更直观 { "$project": { "_id": 0, "completedHouseCount": "$total" } } ])
内容的提问来源于stack exchange,提问作者Bryan Masias
相关产品推荐
相关产品推荐

