Mongo AddToSet multiple objects into one array

aggregation-framework, mongodb, mongodb-query, pymongo

Solution

You can try below solutions based on mongo version.

The idea here is to change the dynamic keys into labeled key value structure i.e. change embedded doc `info_1` & `info_2` into embedded arrays and followed by `$unwind` & `$group`.

Mongo Version 3.4

You can use `$objectToArrays` operator to convert embedded documents into embedded arrays.

db.collection.aggregate({
    $addFields: {
        information: {
            $objectToArray: "$information.info_details"
        }
    }
}, {
    $unwind: "$information"
}, {
    $group: {
        _id: {
            question: "$question",
            answer: "$answer",
            user: "$user"
        },
        info: {
            $addToSet: "$information.v"
        }
    }
})

Mongo Version 3.2

You can use `[]` brackets to do something similar to convert embedded documents into embedded arrays.

db.collection.aggregate({
    $project: {
        question: 1,
        answer: 1,
        user: 1,
        information: ["$information.info_details.info_1", "$information.info_details.info_2"]
    }
}, {
    $unwind: "$information"
}, {
    $group: {
        _id: {
            question: "$question",
            answer: "$answer",
            user: "$user"
        },
        info: {
            $addToSet: "$information"
        }
    }
})

Problem

I'm trying to use $addToSet to add multiple objects to a single array when aggregating in Mongo. The format of the data may not be the best but I don't have the ability to change it. Here is an example of the kinds of documents I'm querying: ``` { "question" : "How tall is the CN Tower?", "answer" : "553.3 metres", "user": "user_1" "information" : { "info_details" : { "info_1" : { "score" : 23, "size" : 855, "total" : 29, }, "info_2" : { "score" : 1234, "size" : 1000, "total" : 3, "index" : "index_1", "rank" : 1 } } } } ``` Below is a sample query ($project section omitted). Though the double $addToSet doesn't work, I put it there as it shows what I want to accomplish logically. Note that the two info objects may have different fields and values. ``` ...{ "$group": { "_id": { "question": "$doc.questionId", "answer": "$doc.answerCandidateId", "user": "$doc.user" }, "info": { "$addToSet": { "score": "$doc.information.info_details.info_1.score", "size": "$doc.information.info_details.info_1.size", "total": "$doc.information.info_details.info_1.total" }, // This second addToSet overwrites the first info value (does not work as I want it to) "info": { "$addToSet": { "score": "$doc.information.info_details.info_2.score", "size": "$doc.information.info_details.info_2.size", "total": "$doc.information.info_details.info_2.total", "index": "$doc.information.info_details.info_2.index", "rank": "$doc.information.info_details.info_2.rank" } } } } } ``` My goal is to have an "info" set with all the info objects (minus duplicates) from the $group operation. ``` { "question": "question_1", "answer": "answer_1", "user": "user_1", "info": [ {"score": 23, "size": 855, "total": 29}, {"score": 1234, "size": 1000, "total": 3, "index": "index_1", "rank": 1}] } ``` Is there a way I can add multiple objects within a $group operation to the same set?

Original source