如何按子文档的字段总和排序

How to sort by a field-sum of a subdocument

...并按过滤条件减少子文档?

我有以下数据结构

{
    "_id" : "PwS8gcfhaWLaudjaJ",
    "name" : "Name of Document 1",
    "subdocuments" : [ 
        {
            "subdocumentsId" : "dqR9gPi7tNvzpEhEW",
            "number" : 1
        }, 
        {
            "subdocumentsId" : "vTaPoQYdaDbqMH7Pg",
            "number" : 1
        }, 
        {
            "subdocumentsId" : "tPJ45KqAzvFPBRstZ",
            "number" : 3
        }
    ]
}
{
    "_id" : "PwS8gcfhaWLaudjaJ",
    "name" : "Name of Document 2",
    "subdocuments" : [ 
        {
            "subdocumentsId" : "dqR9gPi7tNvzpEhEW",
            "number" : 2
        }, 
        {
            "subdocumentsId" : "tPJ45KqAzvFPBRstZ",
            "number" : 5
        }
    ]
}

如何构建查询以获得以下结果

{
    "_id" : "PwS8gcfhaWLaudjaJ",
    "name" : "Name of Document 2",
    "subdocuments" : [ 
        {
            "subdocumentsId" : "dqR9gPi7tNvzpEhEW",
            "number" : 2
        }, 
        {
            "subdocumentsId" : "tPJ45KqAzvFPBRstZ",
            "number" : 5
        }
    ]
}
{
    "_id" : "PwS8gcfhaWLaudjaJ",
    "name" : "Name of Document 1",
    "subdocuments" : [ 
        {
            "subdocumentsId" : "dqR9gPi7tNvzpEhEW",
            "number" : 1
        }, 
        {
            "subdocumentsId" : "tPJ45KqAzvFPBRstZ",
            "number" : 3
        }
    ]
}

...这是我当前的查询

var filterIds = ['dqR9gPi7tNvzpEhEW','tPJ45KqAzvFPBRstZ'];

db.Documents
.aggregate([
{
    $match: {
        'subdocuments.subdocumentsId': {
            $in: filterIds
        }
    }
}, {
    $project: {
        _id: 1,
        name: 1,
        totalNumber: {
            $sum: '$subdocuments.number'
        }
    }
}, {
    $sort: {
        totalNumber: 1
    }
}
])

我无法在 $project-operation 中使用 $sum-expression。它仅适用于 $group。

是否有通用的解决方法,或者是否可以使用 $group 获得结果?

也许有人可以帮忙?

你需要在两者之间使用$unwind when working with arrays. Also you have two $group operations here with a $sort

db.Documents.aggregate([
    // Select documents
    { "$match": {
        "subdocuments.subdocumentsId": {
            "$in": filterIds
        }
    }}, 

    // Denormalize array
    { "$unwind": "subdocuments" }

    // Filter array elements
    { "$match": {
        "subdocuments.subdocumentsId": {
            "$in": filterIds
        }
    }}, 

    // Get array sum      
    { "$group": {
        "_id": {
            "_id": "$_id",
            "name": "$name",
            "subId": "$subdocuments.subdocumentsId"
        },
        "number": { "$sum": "$subdocuments.number" }
     }},

     // Sort the results
     { "$sort": { "_id._id": 1, "number": 1 } },

     // Group back to documents
     { "$group": {
         "_id": "$_id._id",
         "name": { "$first": "$_id.name" },
         "subdocuments": { "$push": {
             "subdocumentsId": "$_id.subId",
             "number": "$number"
         }},
         "total": { "$sum": "$number" }
     }},

     // Sort at the end, decending for largest first
     { "$sort": { "total": -1 } }
])

也就是说,如果您 "summing" 通过其唯一 "subdocumentId" 值过滤结果,而这些值不是唯一的。如果你只是过滤然后减少步骤:

db.Documents.aggregate([
    // Select documents
    { "$match": {
        "subdocuments.subdocumentsId": {
            "$in": filterIds
        }
    }}, 

    // Denormalize array
    { "$unwind": "subdocuments" }

    // Filter array elements
    { "$match": {
        "subdocuments.subdocumentsId": {
            "$in": filterIds
        }
    }}, 

     // Group back to documents
     { "$group": {
         "_id": "$_id",
         "name": { "$first": "$name" },
         "subdocuments": {
            "$push": "$subdocuments"
         },
         "total": { "$sum": "$subdocuments.number" }
     }},

     // Sort at the end, decending for largest first
     { "$sort": { "total": -1 } }
])

请尝试以下查询:

以下是获取结果所遵循的步骤:

1) 展开您的子文档

2) 只保留那些匹配过滤器“filterIds”的文档 " 标准

3) 根据 _id 字段对文档进行分组,并保留 "subdocuments.number" 字段的总和,以便我们可以根据它进行排序。

4) 根据 "subdocuments.number" 字段 (tot) 降序排序。

5) 最终以您需要的格式投影或显示。

db.Documents.aggregate([
{
 $unwind:"$subdocuments"
},
{
 $match:{"subdocuments.subdocumentsId" : {"$in" : filterIds }}
},
{
 $group:{ _id : { id : "$_id", name :"$name" },  
          tot : { "$sum": "$subdocuments.number"} , 
          subdocuments : {"$push" :
                         {subdocumentsId:"$subdocuments.subdocumentsId", 
          number : "$subdocuments.number" } }  } },
{
 $sort:{tot : -1}
},
{
 $project:{_id:"$_id.id", name: "$_id.name", subdocuments:1}
}
]).pretty();

所以上面的查询获取了你想要的结果(输出):

{
        "_id" : "PwS8gcfhaWLaudjaI",
        "subdocuments" : [
                {
                        "subdocumentsId" : "dqR9gPi7tNvzpEhEW",
                        "number" : 2
                },
                {
                        "subdocumentsId" : "tPJ45KqAzvFPBRstZ",
                        "number" : 5
                }
        ],
        "name" : "Name of Document 2"
}
{
        "_id" : "PwS8gcfhaWLaudjaJ",
        "subdocuments" : [
                {
                        "subdocumentsId" : "dqR9gPi7tNvzpEhEW",
                        "number" : 1
                },
                {
                        "subdocumentsId" : "tPJ45KqAzvFPBRstZ",
                        "number" : 3
                }
        ],
        "name" : "Name of Document 1"
}