如何使用MongoDB聚合获取每个组的第一个,包括空值?

时间:2015-12-19 20:39:15

标签: mongodb aggregation-framework

在我的MongoDB people集合中,我需要使用相同的别名来过滤人物#39;财产价值,保留其中的第一个,并使所有人保持空的别名'。

一些示例人数据:

{ "_id" : "1", "flag" : true,  "name" : "Alice",    "alias" : null },
{ "_id" : "2", "flag" : true,  "name" : "Bob",      "alias" : "afa776bea788cf4c" },
{ "_id" : "3", "flag" : true,  "name" : "Bobby",    "alias" : "afa776bea788cf4c" },
{ "_id" : "4", "flag" : true,  "name" : "Cristina", "alias" : null },
{ "_id" : "5", "flag" : false, "name" : "Diego",    "alias" : null },
{ "_id" : "6", "flag" : true,  "name" : "Zoe",      "alias" : "2211293acc82329a" },

这是我期望的结果:

{ "_id" : "1", "name" : "Alice",    "alias" : null },
{ "_id" : "2", "name" : "Bob",      "alias" : "afa776bea788cf4c" },
{ "_id" : "4", "name" : "Cristina", "alias" : null },
{ "_id" : "6", "name" : "Zoe",      "alias" : "2211293acc82329a" },

我已经提到了这个初步查询:

db.people.aggregate({ $group: { _id: '$alias', alias: { $first: '$alias' } } })

我遇到的第一个问题是,这只会返回_idalias字段,但我需要所有字段...

更新: 我更改了一些示例数据以更好地反映我的用例,因为@ user3100115答案解决了旧样本数据的问题,但不能解决实际数据问题。

我做了什么改变:

  • 添加一个带有空别名的文档(" Cristina")(我的文档都有"别名"字段),因为我需要全部要返回null别名值的文档,而不仅仅是第一个。

  • 再添加一个布尔属性(" flag"),我需要能够匹配...即:使用find()我做: db-people.find({flag:true}),但我不明白如何使用aggregate()过滤更多字段...

如果您认为我最好提出一个新问题,请告诉我......

2 个答案:

答案 0 :(得分:2)

如果您需要包括原始_id在内的所有字段,则需要在分组中指定所有字段,然后另外执行投影:

db.entries.aggregate([{ $group: { _id: '$alias', alias: { $first: '$alias' }, name: {$first: '$name'}, id: {$first: '$_id'} } }, {$project: {_id: '$id', name: '$name', alias: '$alias'}}])

答案 1 :(得分:1)

如果您需要所有字段,可以使用$$ROOT来引用根文档。它会将文档的所有字段保存在一个字段中。

Person.aggregate([
    {
        $project:
        {
            alias: {$ifNull: ['$alias', "$_id"] },
            name: 1,
            document: "$$ROOT"
        }
    },
    { $group: { _id: "$alias", name: {$first: "$name"}, document: {$first: "$document"}}},
    {
        $project: { _id:0, document: 1}
    }
], function (err, documents) {
    var result = documents.map(function(doc){
        return doc.document;
    }); 
});