I have a collection of users where each document has following structure:
{ "_id": "<id>", "login": "xxx", "solved": [ { "problem": "<problemID>", "points": 10 }, ... ] }
The field solved
may be empty or contain arbitrary many subdocuments. My goal is to get a list of users together with the total score (sum of points
) where users that haven't solved any problem yet will be assigned total score of 0. Is this possible to do this with a single query (ideally using aggregation framework)?
I was trying to use following query in aggregation framework:
{ "$group": { "_id": "$_id", "login": { "$first": "$login" }, "solved": { "$addToSet": { "points": 0 } } } } { "$unwind": "$solved" } { "$group": { "_id": "$_id", "login": { "$first": "$login" }, "solved": { "$sum": "$solved.points" } } }
However I am getting following error:
exception: The top-level _id field is the only field currently supported for exclusion
Thank you in advance
The $unwind operator is used to deconstructing an array field in a document and create separate output documents for each item in the array. The only difference between input and output documents is that the value of the array field in output documents is replaced with a single item from the input document array.
As you can unwind more than one arrays in single aggregation pipeline. first unwind->group->count, then repeat it for another array in same pipeline. okay let me try, I will then post the query as well as the output..
preserveNullAndEmptyArrays option Defining the “preserveNullAndEmptyArrays” option in a $unwind operation allows the user to include documents where the array field is missing, null, or an empty array. The “preserveNullAndEmptyArrays” option only takes Boolean arguments like true or false.
With MongoDB 3.2 version and newer, the $unwind
operator now has some options where in particular the preserveNullAndEmptyArrays
option will solve this.
If this option is set to true and if the path is null, missing, or an empty array, $unwind
outputs the document. If false, $unwind
does not output a document if the path is null, missing, or an empty array. In your case, set it to true:
db.collection.aggregate([ { "$unwind": { "path": "$solved", "preserveNullAndEmptyArrays": true } }, { "$group": { "_id": "$_id", "login": { "$first": "$login" }, "solved": { "$sum": "$solved.points" } } } ])
Here is the solution - it assumes that the field "solved" is either absent, is equal to null or has an array of problems and scores solved. The case it does not handle is "solved" being an empty array - although that would be a simple additional adjustment you could add.
project = {$project : { "s" : { "$ifNull" : [ "$solved", [ { "points" : 0 } ] ] }, "login" : 1 } }; unwind={$unwind:"$s"}; group= { "$group" : { "_id" : "$_id", "login" : { "$first" : "$login" }, "score" : { "$sum" : "$s.points" } } }
db.students.aggregate( [ project, unwind, group ] );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With