简体   繁体   中英

MongoDB: how to aggregate array field that may be missing

How do I get MongoDB to calculate the sum of array values when the array field may be missing completely (as is the case for month 10)?

For example:

> db.month.save({MonthNum: 10, 
...              NumWeekdays: 23});
> db.month.save({MonthNum: 11, 
...              NumWeekdays: 21,
...              Holidays: [ {Description: "Thanksgiving",   NumDays: 2} ] });
> db.month.save({MonthNum: 12, 
...              NumWeekdays: 22,
...              Holidays: [ {Description: "Christmas",      NumDays: 6},
...                          {Description: "New Year's Eve", NumDays: 1} ] });
> db.month.aggregate( { $unwind: "$Holidays" }, 
...                   { $group: { _id: "$MonthNum", 
...                               total: { $sum: "$Holidays.NumDays" } } });
{
    "result" : [
        {
            "_id" : 12,
            "total" : 7
        },
        {
            "_id" : 11,
            "total" : 2
        }
    ],
    "ok" : 1
}

How do I get month 10 to show up in the above results (showing "total" as 0)?

Bonus: How do I get the above to show the available weekdays (the NumWeekdays minus the sum of the Holidays)?

I've tried $project to get the data into a canonical format first but without success so far... thanks!

$unwind isn't passing along your document with MonthNum 10 because your Holidays array is empty on that document (see the note at the bottom of the $unwind docs ). Assuming that Holidays is always either an array containing at least one item or completely absent from a document, you can use the $ifNull operator inside of $project to add a "Holiday" document that just has NumDays = 0 to your Holidays is null:

db.month.aggregate([
    // Make "Holidays" = [{NumDays:0}] if "Holidays" is null for this document (i.e. absent)
    {$project:{NumWeekDays:1, MonthNum:1, Holidays:{$ifNull:["$Holidays", [{"NumDays":0}]]}}},
    // Now you can unwind + group as normal
    {$unwind:"$Holidays"},
    {$group:{_id:"$MonthNum", NumWeekDays:{$first:"$NumWeekDays"}, "total":{$sum:"$Holidays.NumDays"}}},
    // This should take care of "available weekdays"
    {$project:{total:1, available:{$subtract:["$NumWeekDays", "$total"]}}}
]);

Note that $ifNull won't work if for some of your documents Holidays is an empty array; it has to be absent completely.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM