'Grouping documents only when all group members match criteria on MongoDB
I have an example set of documents like so:
/* 1 */
{
"_id" : ObjectId("61c50482f176d72cb660baa3"),
"answer" : "yes",
"answerTo" : ObjectId("61c5047ef176d72cb660ba98"),
"answeredBy" : ObjectId("61c117cc93361c38912e91d9"),
"picked" : false,
"createdTimestamp" : Timestamp(1640301698, 1)
}
/* 2 */
{
"_id" : ObjectId("61c50484f176d72cb660baac"),
"answer" : "kinda",
"answerTo" : ObjectId("61c5047ef176d72cb660ba98"),
"answeredBy" : ObjectId("61c117cc93361c38912e91d9"),
"picked" : true,
"createdTimestamp" : Timestamp(1640301700, 1)
}
/* 3 */
{
"_id" : ObjectId("61c50486f176d72cb660bab5"),
"answer" : "no",
"answerTo" : ObjectId("61c5047ef176d72cb660ba98"),
"answeredBy" : ObjectId("61c117cc93361c38912e91d9"),
"picked" : false,
"createdTimestamp" : Timestamp(1640301702, 1)
}
/* 4 */
{
"_id" : ObjectId("62018461f520338a2fc78740"),
"answer" : "yes",
"answerTo" : ObjectId("620182c4f520338a2fc78675"),
"answeredBy" : ObjectId("61c117cc93361c38912e91d9"),
"picked" : false,
"createdTimestamp" : Timestamp(1644266593, 1)
}
/* 5 */
{
"_id" : ObjectId("6201848af520338a2fc7877b"),
"answer" : "of course!",
"answerTo" : ObjectId("62018486f520338a2fc78772"),
"answeredBy" : ObjectId("61c117cc93361c38912e91d9"),
"picked" : true,
"createdTimestamp" : Timestamp(1644266634, 1)
}
/* 6 */
{
"_id" : ObjectId("6201851bf520338a2fc787e9"),
"answer" : "7",
"answerTo" : ObjectId("62018518f520338a2fc787de"),
"answeredBy" : ObjectId("61c117cc93361c38912e91d9"),
"picked" : true,
"createdTimestamp" : Timestamp(1644266779, 1),
"verification" : true
}
... some more documents
My current aggregation query achieves grouping the documents with picked: false present.
Basically, I'm trying to make a query to group documents by a common answerTo property value. However, while doing so, it should include groups which only have picked: false. Unfortunately, my current query still includes picked: true among those groups.
What am I doing wrong?
Current query:
await db.collection("answers").aggregate(
[
{
$group: {
_id: {
answerTo: "$answerTo"
},
picked: {
$push: "$picked"
},
count: {
$sum: 1
}
}
},
{
$match: {
picked: false
}
}
]
).toArray();
Outputs:
[
{
_id: { answerTo: new ObjectId("62052be3ce58ad9dff5b47d6") },
picked: [ true, false, false, false ],
count: 4
},
{
_id: { answerTo: new ObjectId("61c5047ef176d72cb660ba98") },
picked: [ false, true, false ],
count: 3
},
{
_id: { answerTo: new ObjectId("62052beace58ad9dff5b47f7") },
picked: [ false, false ],
count: 2
},
{
_id: { answerTo: new ObjectId("620182c4f520338a2fc78675") },
picked: [ false ],
count: 1
},
{
_id: { answerTo: new ObjectId("62052c00ce58ad9dff5b4839") },
picked: [ false, false ],
count: 2
}
]
Expected output:
[
{
_id: { answerTo: new ObjectId("62052beace58ad9dff5b47f7") },
picked: [ false, false ],
count: 2
},
{
_id: { answerTo: new ObjectId("620182c4f520338a2fc78675") },
picked: [ false ],
count: 1
},
{
_id: { answerTo: new ObjectId("62052c00ce58ad9dff5b4839") },
picked: [ false, false ],
count: 2
}
]
Solution 1:[1]
You need to place your $match as first in your pipeline. So in the first pipeline, your documents are filtered by $picked: false. In second pipeline your group would give the result as you expected.
await db.collection("answers").aggregate(
[
{
$match: {
picked: false
}
},
{
$group: {
_id: {
answerTo: "$answerTo"
},
picked: {
$push: "$picked"
},
count: {
$sum: 1
}
}
}
]
).toArray();
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Arun |
