如何将对象列表转换为对象的外部新对象?

How to transform a list of objects into an outer new object of objects?

鉴于此课程集合,有一个由对象组成的主题列表。是否可以创建一个聚合来创建一个新字段 newSubjects 以通过其 ID 映射所有主题?例如,给定此集合如何将 subjects 条目从 :

[
  {
    _id: ObjectId("623e2f0cb242ee9367eb3c9f"),
    subjects: [ { id: '1', name: 'math' }, { id: '2', name: 'physics' } ]
  },
  {
    _id: ObjectId("623e2f17b242ee9367eb3ca0"),
    subjects: [ { id: '1', name: 'math' }, { id: '3', name: 'biology' } ]
  }
]

进入:

{
  newSubjects: { '1': { id: '1', name: 'math' }, '2': { id: '2', name: 'physics' } }
}
{
  newSubjects: { '1': { id: '1', name: 'math' }, '3': { id: '3', name: 'biology' } }
}

使用 JavaScript 我可以用这个表达式来做:

db.courses.find().forEach(x => print({"newSubjects": Object.fromEntries(new Map(x.subjects.map(s => [s.id, s])))}))

我正在尝试找出一个聚合来完成此操作,但 $addField$map 尚未成功。

您可以试试这个查询:

只需要一个聚合阶段就可以合成你想要的结果。在此阶段,您可以使用 $map 对每个值进行迭代,并使用 return 一个新值。这个新的将有 kv 字段。

  • k 字段将是对象键 (1, 2, 3...)
  • v 字段将是值字段(具有 {id:..., name:...} 的对象)

并由 $arrayToObject 包装以将 kv 翻译成所需的对象。

db.collection.aggregate([
  {
    "$project": {
      "_id": 0,
      "newSubjects": {
        "$arrayToObject": {
          "$map": {
            "input": "$$ROOT.subjects",
            "in": {
              "k": "$$this.id",
              "v": {
                "id": "$$this.id",
                "name": "$$this.name"
              }
            }
          }
        }
      }
    }
  }
])

示例here

另一个选项:

 db.collection.aggregate([
{
"$project": {
  "newSubjects": {
    "$arrayToObject": {
      "$map": {
        "input": "$subjects",
        "as": "s",
        "in": {
          k: "$$s.id",
          v: "$$s"
        }
       }
      }
     }
    }
   }
 ])

解释:

用适合 arrayToObject 投影为 newSubjects 的必要 k,v 映射数组

playground