如何将两个对象数组合并为一个对象集合在MongoDB中?

huangapple go评论49阅读模式
英文:

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

假设你的两个数组中的对象完全相同(即_idname都相同,且没有其他字段),你可以使用$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"
    }
  }
])

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

答案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

huangapple
  • 本文由 发表于 2023年2月8日 22:59:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/75387629.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定