英文:
How do I merge two Arrays of objects into one Set of objects in MongoDB?
问题
以下是facet阶段后的结果:
{
    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
        }
    ]
}
我想要将两个数组中的对象添加到一个集合中(以避免重复),然后展开它们,以便得到每个对象的单独文档,如下所示:
{
    _id: ObjectId('6139f794f6a0af371900dbfh'),
    name: MyComputer_1
}
____
{
    _id: ObjectId('6319bd1540b41d1a35717a16'),
    name: MyComputer_2
}
____
{
    _id: ObjectId('61f39f8ae2daa732deff6d90'),
    name: MyComputer_3
}
如何实现这个目标?
英文:
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?
答案1
得分: 1
假设你的两个数组中的对象完全相同(即_id和name都相同,且没有其他字段),你可以使用$setUnion构建并集。然后使用$unwind和$replaceRoot:
db.collection.aggregate([
  {
    "$project": {
      allComputers: {
        "$setUnion": [
          "$directComputers",
          "$indirectComputers"
        ]
      }
    }
  },
  {
    "$unwind": "$allComputers"
  },
  {
    "$replaceRoot": {
      "newRoot": "$allComputers"
    }
  }
])
如果你希望根据某个关键字段(比如这里的_id)进行比较,你可以使用$reduce构建并集:
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"
    }
  }
])
英文:
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"
    }
  }
])
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"
    }
  }
])
答案2
得分: 0
如果您希望结果展开,可以执行以下操作:
db.collection.aggregate([
{$project: {
_id: 0,
data: {$concatArrays: ["$directComputers", "$indirectComputers"]}
}},
{$unwind: "$data"},
{$group: {_id: "$data._id", name: {$first: "$data.name"}}}
])
请在[playground示例](https://mongoplayground.net/p/veDbvtjh9Tk)上查看其运行方式
另一个更通用的选项是(适用于不需要 `$unwind` 的情况):
db.collection.aggregate([
{$project: {
_id: 0,
data: {$setUnion: ["$directComputers", "$indirectComputers"]}
}},
{$unwind: "$data"},
{$replaceRoot: {newRoot: "$data"}}
])
请在[playground示例](https://mongoplayground.net/p/T6HtKhdtmHc)上查看其运行方式
英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论