Vince
Vince

Reputation: 367

Mongo AddToSet multiple objects into one array

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?

Upvotes: 5

Views: 13082

Answers (1)

s7vr
s7vr

Reputation: 75914

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"
        }
    }
})

Upvotes: 7

Related Questions