计算其他集合中的_id出现次数

时间:2018-09-25 19:38:43

标签: mongodb aggregation-framework

我们具有类似于以下内容的数据库结构:

宠物主人:

/* 1 */
{
    "_id" : ObjectId("5baa8b8ce70dcbe59d7f1a32"),
    "name" : "bob"
}

/* 2 */
{
    "_id" : ObjectId("5baa8b8ee70dcbe59d7f1a33"),
    "name" : "mary"
}

宠物:

/* 1 */
{
    "_id" : ObjectId("5baa8b4fe70dcbe59d7f1a2a"),
    "name" : "max",
    "owner" : ObjectId("5baa8b8ce70dcbe59d7f1a32")
}

/* 2 */
{
    "_id" : ObjectId("5baa8b52e70dcbe59d7f1a2b"),
    "name" : "charlie",
    "owner" : ObjectId("5baa8b8ce70dcbe59d7f1a32")
}

/* 3 */
{
    "_id" : ObjectId("5baa8b53e70dcbe59d7f1a2c"),
    "name" : "buddy",
    "owner" : ObjectId("5baa8b8ee70dcbe59d7f1a33")
}

我需要列出所有宠物主人以及他们所拥有的宠物数量。我们当前的查询类似于以下内容:

db.getCollection('owners').aggregate([
    { $lookup: { from: 'pets', localField: '_id', foreignField: 'owner', as: 'pets' } },
    { $project: { '_id': 1, name: 1, numPets: { $size: '$pets' } } }
]);

这行得通,但是它很慢,我问自己是否有一种更有效的查询方法?

[更新和反馈] 。感谢您的回答。该解决方案有效,但是遗憾的是,与上述查询相比,我看不到任何性能改进。显然,MongoDB仍然需要扫描整个宠物收集。我的希望是,可以以某种方式利用owner集合上的pets索引(存在)来获取计数(不需要触摸宠物文档),但这似乎并没有就是这种情况。

除了将计数明确存储在所有者文档中之外,是否还有其他想法或解决方案可用于快速检索“宠物计数”?

2 个答案:

答案 0 :(得分:1)

在MongoDB 3.6中,您可以创建自定义$lookup管道并计数而不是整个pets文档,请尝试:

db.owners.aggregate([
    {
        $lookup: {
            from: "pets",
            let: { ownerId: "$_id" },
            pipeline: [
                { $match: { $expr: { $eq: [ "$$ownerId", "$owner" ] } } },
                { $count: "count" }
            ],
            as: "numPets"
        }
    },
    {
        $unwind: "$numPets"
    }
])

答案 1 :(得分:1)

您可以尝试以下汇总

db.owners.aggregate([
  { "$lookup": {
    "from": "pets",
    "let": { "ownerId": "$_id" },
    "pipeline": [
      { "$match": { "$expr": { "$eq": [ "$$ownerId", "$owner" ] }}},
      { "$count": "count" }
    ],
    "as": "numPets"
  }},
  { "$project": {
    "_id": 1,
    "name": 1,
    "numPets": { "$ifNull": [{ "$arrayElemAt": ["$numPets.count", 0] }, 0]}
  }}
])