Reputation: 8407
I'm using an example from mongo docs which I've changed a bit:
db.books.aggregate(
[
{ $group : { _id : "$genre", books: { $push: "$$ROOT" } } }
]
)
This query will return an array of books by genre.
I want to customise it a bit, so that I would not get extra data. The following example would be a dummy one, but I'm curious if it could be implemented in mongo. I want my aggregation to return an array of groups where if genre
is 'Tragedy' only 1 book would be fetched and there would be a booksCount
field and in all the other cases books
will be an array and there won't be a booksCount
.
So the aggregation result would look something like this:
[
{ _id: '_id of tragedy genre', book: {some book}, booksCount: some int },
{ _id: '_id of some other genre', books: [books] },
...
]
So I want groups to have different keys depending on some condition
Upvotes: 0
Views: 53
Reputation: 1402
One way to do this is with the $facet
aggregation pipeline stage. This stage allows us to create multiple pipelines with the same input documents. In this case we have one pipeline for the tragedy genre and another for all the other genres. In order to get your desired output we need to merge the two pipeline stages. From the docs:
Each sub-pipeline has its own field in the output document where its results are stored as an array of documents.
Because the facet stage returns an array of documents for each pipeline, we need to: concatenate these arrays together, unwind the resulting array so that each element is its own document, and then replace the root of each document to get rid of the unwanted key.
Say you have the following documents:
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"
}])
Then you can use the following query:
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"}
}])
To produce:
{
"_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"
}
]
}
Upvotes: 1