Merging array fields in MongoDB aggregation

前端 未结 2 1954
谎友^
谎友^ 2021-02-07 13:51

Is it possible to merge array fields in while using MongoDB aggregation framework? Here is a summary problem I am trying to solve:

Sample input documents for aggregation

相关标签:
2条回答
  • 2021-02-07 14:17

    Here is a trick you can use if Messages is guaranteed to be an array:

    > db.messages.find()
        { "Category" : 1, "Messages" : [  "Msg1",  "Msg2" ], "Value" : 1 }
        { "Category" : 1, "Messages" : [ ], "Value" : 10 }
        { "Category" : 1, "Messages" : [  "Msg1",  "Msg3" ], "Value" : 100 }
        { "Category" : 2, "Messages" : [  "Msg4" ], "Value" : 1000 }
        { "Category" : 2, "Messages" : [  "Msg5" ], "Value" : 10000 }
        { "Category" : 3, "Messages" : [ ], "Value" : 100000 }
    
    > var group1 = {
        "$group":   {
            "_id":      "$Category",
            "Value":    {
                "$sum":     "$Value"
            },
            "Messages": {
                "$push":    "$Messages"
            }
        }
    };
    
    > var project1 = {
        "$project": {
            "Value":    1,
            "Messages": {
                "$cond":    [
                    {
                        "$eq":  [
                            "$Messages",
                            [ [ ] ]
                        ]
                    },
                    [ [ null ] ],
                    "$Messages"
                ]
            }
        }
    };
    
    > db.messages.aggregate( group1, project1 )
        { "_id" : 3, "Value" : 100000, "Messages" : [  [  null ] ] }
        { "_id" : 2, "Value" : 11000, "Messages" : [  [  "Msg4" ],  [  "Msg5" ] ] }
        { "_id" : 1, "Value" : 111, "Messages" : [  [  "Msg1",  "Msg2" ],  [ ],  [  "Msg1",  "Msg3" ] ] }
    

    Now unwind twice and re-group to get a single Messages array.

    > var unwind = {"$unwind":"$Messages"};
    
    > var group2 = {
        $group: {
            "_id":      "$_id", 
            "Value":    {
                "$first":       "$Value"
            }, 
            "Messages": {
                "$addToSet":    "$Messages"
            }
        }
    };
    
    > var project2 = {
        "$project": {
            "Category": "$_id",
            "_id":      0,
            "Value":    1,
            "Messages": {
                "$cond":    [
                    {
                        "$eq":  [
                            "$Messages",
                            [ null ]
                        ]
                    },
                    [ ],
                    "$Messages"
                ]
            }
        }
    };
    
    > db.messages.aggregate(group1, project1, unwind, unwind, group2 ,project2 )
        { "Value" : 111, "Messages" : [  "Msg3",  "Msg2",  "Msg1" ], "Category" : 1 }
        { "Value" : 11000, "Messages" : [  "Msg5",  "Msg4" ], "Category" : 2 }
        { "Value" : 100000, "Messages" : [ ], "Category" : 3 }
    
    0 讨论(0)
  • 2021-02-07 14:35

    As already mentioned in one of the comments, the simplest answer to the original question is to add preserveNullAndEmptyArrays to the $unwind stage.

    0 讨论(0)
提交回复
热议问题