TheStranger
TheStranger

Reputation: 1577

How do I merge two Arrays of objects into one Set of objects in MongoDB?

I have the following result after a facet stage:

{
    directComputers: [
        {
            _id: ObjectId('6139f794f6a0af371900dbfh'),
            name: MyComputer_1
        },
        {
            _id: ObjectId('6319bd1540b41d1a35717a16'),
            name: MyComputer_2
        }
    ],
    indirectComputers: [
        {
            _id: ObjectId('6319bd1540b41d1a35717a16'),
            name: MyComputer_2
        },
        {
            _id: ObjectId('61f39f8ae2daa732deff6d90'),
            name: MyComputer_3
        }
    ]

I'm trying to add the objects from both arrays into a set (to avoid duplicates), and then unwind so I end up with one separate document for each object.

Like this:

{
    _id: ObjectId('6139f794f6a0af371900dbfh'),
    name: MyComputer_1
}

{
    _id: ObjectId('6319bd1540b41d1a35717a16'),
    name: MyComputer_2
}

{
    _id: ObjectId('61f39f8ae2daa732deff6d90'),
    name: MyComputer_3
}

How do I achieve that?

Upvotes: 0

Views: 177

Answers (2)

ray
ray

Reputation: 15217

Assuming the objects inside your 2 arrays are completely identical(i.e. both _id and name is the same and contains no other fields), you can use $setUnion to construct the union. Then $unwind and $replaceRoot

db.collection.aggregate([
  {
    "$project": {
      allComputers: {
        "$setUnion": [
          "$directComputers",
          "$indirectComputers"
        ]
      }
    }
  },
  {
    "$unwind": "$allComputers"
  },
  {
    "$replaceRoot": {
      "newRoot": "$allComputers"
    }
  }
])

Mongo Playground


If you would rather compare with some key field, says _id in this case, you can use $reduce to construct the union.

db.collection.aggregate([
  {
    "$project": {
      allComputers: {
        "$reduce": {
          "input": "$indirectComputers",
          "initialValue": "$directComputers",
          "in": {
            "$cond": {
              "if": {
                "$in": [
                  "$$this._id",
                  "$$value._id"
                ]
              },
              "then": "$$value",
              "else": {
                "$concatArrays": [
                  "$$value",
                  [
                    "$$this"
                  ]
                ]
              }
            }
          }
        }
      }
    }
  },
  {
    "$unwind": "$allComputers"
  },
  {
    "$replaceRoot": {
      "newRoot": "$allComputers"
    }
  }
])

Mongo Playground

Upvotes: 1

nimrod serok
nimrod serok

Reputation: 16033

Since you want the results unwinded you can do:

db.collection.aggregate([
  {$project: {
      _id: 0,
      data: {$concatArrays: ["$directComputers", "$indirectComputers"]}
  }},
  {$unwind: "$data"},
  {$group: {_id: "$data._id", name: {$first: "$data.name"}}}
])

See how it works on the playground example

Another option is which is more generic (for cases where $unwind is not needed):

db.collection.aggregate([
  {$project: {
      _id: 0,
      data: {$setUnion: ["$directComputers", "$indirectComputers"]}
  }},
  {$unwind: "$data"},
  {$replaceRoot: {newRoot: "$data"}}
])

See how it works on the playground example

Upvotes: 0

Related Questions