在聚合期间自定义mongo中的组

时间:2019-02-05 19:30:47

标签: mongodb

我使用的是mongo文档中的示例,但我对其进行了一些更改:

db.books.aggregate(
   [
     { $group : { _id : "$genre", books: { $push: "$$ROOT" } } }
   ]
)

此查询将按流派返回一系列图书。

我想对其进行一些自定义,这样我就不会得到额外的数据。以下示例将是一个虚拟示例,但我很好奇它是否可以在mongo中实现。我希望我的汇总返回一组数组,如果genre为“悲剧”,则只会获取一本书,并且会有一个booksCount字段,而在所有其他情况下,books会是一个数组,就不会有booksCount

所以聚合结果看起来像这样:

[
  { _id: '_id of tragedy genre', book: {some book}, booksCount: some int },
  { _id: '_id of some other genre', books: [books] },
  ...
]

所以我希望组根据某些条件具有不同的键

1 个答案:

答案 0 :(得分:1)

一种实现方法是使用$facet聚合管道阶段。此阶段使我们可以使用相同的输入文档创建多个管道。在这种情况下,悲剧类型有一个管道,所有其他类型都有一个管道。为了获得所需的输出,我们需要合并两个管道阶段。从文档中:

  

每个子管道在输出文档中都有自己的字段,其结果存储为文档数组。

因为facet阶段为每个管道返回了一个文档数组,所以我们需要:将这些数组连接在一起,展开结果数组,使每个元素成为自己的文档,然后替换每个文档的根目录以摆脱不需要的密钥。

示例

假设您有以下文件:

db.books.insertMany([{
    genre: "Tragedy",
    title: "Romeo and Juliet"
}, {
    genre: "Tragedy",
    title: "Titanic"
}, {
    genre: "Comedy",
    title: "Hitchhikers Guide to the Galaxy"
}, {
    genre: "Comedy",
    title: "Blazing Saddles"
}, {
    genre: "Thriller",
    title: "Shutter Island"
}, {
    genre: "Thriller",
    title: "Hannibal"
}])

然后您可以使用以下查询:

db.books.aggregate([{
    $facet: {
        tragedy: [{
            $match: {genre: "Tragedy"}
        }, {
            $group: {
                _id: "$genre",
                books: {$push: "$$ROOT"}
            }
        }, {
            $project: {
                book: {$arrayElemAt: ["$books", 1]},
                booksCount: {$size: "$books"}
            }
        }],
        other: [{
            $match: {
                genre: {$ne: "Tragedy"}
            } 
        }, {
            $group: {
                _id: "$genre",
                books: {$push: "$$ROOT"}
            }
        }]
    }
}, {
    $project: {
        documents: {$concatArrays: ["$tragedy", "$other"]}  
    }
}, {
    $unwind: "$documents"
}, {
    $replaceRoot: {newRoot: "$documents"}
}])

产生:

{
    "_id" : "Tragedy",
    "book" : {
        "_id" : ObjectId("5c59f15bc59454560b36a5c7"),
        "genre" : "Tragedy",
        "title" : "Titanic"
    },
    "booksCount" : 2
}
{
    "_id" : "Thriller",
    "books" : [
        {
            "_id" : ObjectId("5c59f15bc59454560b36a5ca"),
            "genre" : "Thriller",
            "title" : "Shutter Island"
        },
        {
            "_id" : ObjectId("5c59f15bc59454560b36a5cb"),
            "genre" : "Thriller",
            "title" : "Hannibal"
        }
    ]
}
{
    "_id" : "Comedy",
    "books" : [
        {
            "_id" : ObjectId("5c59f15bc59454560b36a5c8"),
            "genre" : "Comedy",
            "title" : "Hitchhikers Guide to the Galaxy"
        },
        {
            "_id" : ObjectId("5c59f15bc59454560b36a5c9"),
            "genre" : "Comedy",
            "title" : "Blazing Saddles"
        }
    ]
}