skip to Main Content

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?

2

Answers


  1. 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

    Login or Signup to reply.
  2. 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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search