Search code examples
mongodbmongodb-querymongodb-compass

How to convert two array into an object in mongoDB where the first array has multiple same values


After some processing with a mongo aggregation, I have a collection like :

[{
 field1: 10,
 field2: 50,
 field3: { 
           name: ["a","b","a","a"], 
           value: [1,2,3,4]
         }
},...]

I am struggling finding a way to convert it into :

[{
 field1: 10,
 field2: 50,
 a:[1,3,4],
 b:[2]
},...]

Using mongo aggregation in mongoshell or compass


Solution

  • So the idea is to:

    1. Pick one of the array from field3 say name to generate array range [0, 1, 2, 3].
    2. Loop through name and value array simultaneously to get an array of { k: "", v: "" }.
    3. $unwind the array from previous stage for grouping.
    4. Group by key field3.k to accumulate all values field3.v.
    5. Again group by null to generate an array of pattern { k: "", v: "" }.
    6. Concatenate field1 and field2 into the array from previous stage.
    7. Finally convert the array to object using $arrayToObject.

    Try this:

    db.testCollection.aggregate([
        {
            $addFields: {
                field3: {
                    $map: {
                        input: { $range: [0, { $size: "$field3.name" }] },
                        as: "index",
                        in: {
                            k: { $arrayElemAt: ["$field3.name", "$$index"] },
                            v: { $arrayElemAt: ["$field3.value", "$$index"] }
                        }
                    }
                }
            }
        },
        { $unwind: "$field3" },
        {
            $group: {
                _id: "$field3.k",
                field1: { $first: "$field1" },
                field2: { $first: "$field2" },
                k: { $first: "$field3.k" },
                v: { $push: "$field3.v" }
            }
        },
        {
            $group: {
                _id: null,
                field1: { $first: "$field1" },
                field2: { $first: "$field2" },
                array: {
                    $push: { k: "$k", v: "$v" }
                }
            }
        },
        {
            $addFields: {
                array: {
                    $concatArrays: [
                        [{ k: "field1", v: "$field1" }, { k: "field2", v: "$field2" }],
                        "$array"
                    ]
                }
            }
        },
        {
            $replaceRoot: {
                newRoot: { $arrayToObject: "$array" }
            }
        }
    ]);
    

    Output

    {
        "field1" : 10,
        "field2" : 50,
        "a" : [
            1,
            3,
            4
        ],
        "b" : [
            2
        ]
    }