我们有三个嵌套数组:

  1. principalCredits,带2个对象
  2. credits个,每个对象2个
  3. awardNominations.edges,总计从0到3不等

任务是基于eventsCollection的查找向第三个对象数组awardNominations.edges添加字段.

以下是我拥有的数据(经过简化,可以复制并粘贴到MongoDB Compass中):

[{
  "principalCredits": [
    {
      "category": {
        "id": "director",
        "text": "Directors"
      },
      "totalCredits": 2,
      "credits": [
        {
          "name": {
            "id": "nm11813828",
            "nameText": {
              "text": "Pippa Ehrlich"
            },
            "awardNominations": {
              "total": 2,
              "edges": [
                {
                  "node": {
                    "id": "an1393007",
                    "isWinner": true,
                    "award": {
                      "id": "an1393007",
                      "year": 2020,
                      "text": "Green Warsaw Award",
                      "event": {
                        "id": "ev0003786",
                        "text": "Millennium Docs Against Gravity"
                      },
                      "category": {
                        "text": null
                      }
                    }
                  }
                },
                {
                  "node": {
                    "id": "an1428940",
                    "isWinner": false,
                    "award": {
                      "id": "an1428940",
                      "year": 2021,
                      "text": "IDA Award",
                      "event": {
                        "id": "ev0000351",
                        "text": "International Documentary Association"
                      },
                      "category": {
                        "text": "Best Writing"
                      }
                    }
                  }
                },
              ]
            }
          },
          "category": {
            "id": "director",
            "text": "Director"
          }
        },
        {
          "name": {
            "id": "nm1624755",
            "nameText": {
              "text": "James Reed"
            },
            "awardNominations": {
              "total": 3,
              "edges": [
                {
                  "node": {
                    "id": "an0694012",
                    "isWinner": true,
                    "award": {
                      "id": "an0694012",
                      "year": 2015,
                      "text": "Best of Festival",
                      "event": {
                        "id": "ev0001486",
                        "text": "Jackson Wild Media Awards"
                      },
                      "category": {
                        "text": "Best of Festival"
                      }
                    }
                  }
                },
                {
                  "node": {
                    "id": "an0975779",
                    "isWinner": true,
                    "award": {
                      "id": "an0975779",
                      "year": 2017,
                      "text": "RTS West Television Award",
                      "event": {
                        "id": "ev0000571",
                        "text": "Royal Television Society, UK"
                      },
                      "category": {
                        "text": "Documentary"
                      }
                    }
                  }
                },
                {
                  "node": {
                    "id": "an0975781",
                    "isWinner": true,
                    "award": {
                      "id": "an0975781",
                      "year": 2015,
                      "text": "Grand Teton Prize",
                      "event": {
                        "id": "ev0001356",
                        "text": "Jackson Hole Film Festival"
                      },
                      "category": {
                        "text": "Best in Festival"
                      }
                    }
                  }
                }
              ]
            }
          },
          "category": {
            "id": "director",
            "text": "Director"
          }
        }
      ]
    },
    {
      "category": {
        "id": "writer",
        "text": "Writers"
      },
      "totalCredits": 2,
      "credits": [
        {
          "name": {
            "id": "nm11813828",
            "nameText": {
              "text": "Pippa Ehrlich"
            },
            "awardNominations": {
              "total": 2,
              "edges": [
                {
                  "node": {
                    "id": "an1393007",
                    "isWinner": true,
                    "award": {
                      "id": "an1393007",
                      "year": 2020,
                      "text": "Green Warsaw Award",
                      "event": {
                        "id": "ev0003786",
                        "text": "Millennium Docs Against Gravity"
                      },
                      "category": {
                        "text": null
                      }
                    }
                  }
                },
                {
                  "node": {
                    "id": "an1428940",
                    "isWinner": false,
                    "award": {
                      "id": "an1428940",
                      "year": 2021,
                      "text": "IDA Award",
                      "event": {
                        "id": "ev0000351",
                        "text": "International Documentary Association"
                      },
                      "category": {
                        "text": "Best Writing"
                      }
                    }
                  }
                }
              ]
            }
          },
          "category": {
            "id": "writer",
            "text": "Writer"
          },
        },
        {
          "name": {
            "id": "nm1624755",
            "nameText": {
              "text": "James Reed"
            },
            "awardNominations": {
              "total": 0,
              "edges": []
            }
          },
          "category": {
            "id": "writer",
            "text": "Writer"
          },
        }
      ]
    }
  ]
}]

获奖示例如下:

{
  "id": "an0975781",
  "isWinner": true,
  "award": { ... },
  "score": 1.5
}

一旦完成所有操作,数据需要与最初的形状完全相同,并且没有空值.所以在最后一个数组awardsNominations.edges的情况下,它应该是[],而不是{ node: { score: null }}或其他任何东西.

为了实现这一点,我创建了一个聚合管道:

[
  {
    '$unwind': {
      'path': '$principalCredits', 
      'preserveNullAndEmptyArrays': true
    }
  }, {
    '$unwind': {
      'path': '$principalCredits.credits', 
      'preserveNullAndEmptyArrays': true
    }
  }, {
    '$unwind': {
      'path': '$principalCredits.credits.name.awardNominations.edges', 
      'preserveNullAndEmptyArrays': true
    }
  }, {
    '$lookup': {
      'from': 'eventsCollection', 
      'localField': 'principalCredits.credits.name.awardNominations.edges.node.award.event.id', 
      'foreignField': 'id',
      'as': 'matchingEvent'
    }
  }, {
    '$unwind': {
      'path': '$matchingEvent', 
      'preserveNullAndEmptyArrays': true
    }
  }, {
    '$addFields': {
      'principalCredits.credits.name.awardNominations.edges.node.score': {
        '$multiply': [
          '$matchingEvent.importance', {
            '$cond': {
              'if': '$principalCredits.credits.name.awardNominations.edges.node.isWinner', 
              'then': 1.5, 
              'else': 1.2
            }
          }
        ]
      }
    }
  }
]

上述管道将score分配给每个奖励.然而,空值仍然存在,我完全不知道如何将其恢复到一起.我曾try 与以下群体合作:

{
  '$group': {
    '_id': '$id', 
    'titleDoc': {
      '$first': '$$ROOT'
    }, 
    'allPrincipalCredits': {
      '$push': '$principalCredits'
    }
  }
}

保留根,然后以某种方式将所有记录排序回形状,但无法返回到原始对象 struct .

任何有助于把这一切放在一起的人都将不胜感激!

我很擅长简单的聚合,但这对我来说似乎太多了,我很想学习如何正确地返回$group个东西.

我试着把迄今为止从不同来源和类似答案获得的所有知识整合在一起,但似乎无法实现.

查找集合eventsCollection包含以下对象:

{  
  "_id": { "$oid": "62c57125d6943d92f83f6fff" },  
  "id": "ev0030197",  
  "text": "#AmLatino Film Festival",  
  "importance": 1
}

推荐答案

因此,恢复到原始 struct 的"规则"是,对于每$unwind个"解构"文档,您现在必须执行$group个操作来恢复它.

可以想象,在这样的管道中,这可能会非常麻烦.但绝对可行.

(很小的一点不是你的分数仍然是null的原因是因为你的$multiply函数有语法错误)

无论如何,我们的 idea 是首先收集嵌套文档中存在的所有唯一事件ID.

Mongo Playground

db.collection.aggregate([
  {
    $addFields: {
      allEvents: {
        $reduce: {
          input: {
            $map: {
              input: "$principalCredits",
              in: {
                $map: {
                  input: "$$this.credits",
                  as: "credit",
                  in: {
                    $map: {
                      input: "$$credit.name.awardNominations.edges",
                      as: "edge",
                      in: "$$edge.node.award.event.id"
                    }
                  }
                }
              }
            }
          },
          initialValue: [],
          in: {
            "$concatArrays": [
              {
                "$reduce": {
                  input: "$$this",
                  initialValue: [],
                  in: {
                    "$concatArrays": [
                      "$$this",
                      "$$value"
                    ]
                  }
                }
              },
              "$$value"
            ]
          }
        }
      }
    }
  },
  {
    "$lookup": {
      "from": "eventsCollection",
      "localField": "allEvents",
      "foreignField": "id",
      "as": "matchingEvents"
    }
  },
  {
    $addFields: {
      principalCredits: {
        $map: {
          input: "$principalCredits",
          in: {
            $mergeObjects: [
              "$$this",
              {
                credits: {
                  $map: {
                    input: "$$this.credits",
                    as: "credit",
                    in: {
                      $mergeObjects: [
                        "$$credit",
                        {
                          name: {
                            "$mergeObjects": [
                              "$$credit.name",
                              {
                                "awardNominations": {
                                  "$mergeObjects": [
                                    "$$credit.name.awardNominations",
                                    {
                                      edges: {
                                        $map: {
                                          input: "$$credit.name.awardNominations.edges",
                                          as: "edge",
                                          in: {
                                            node: {
                                              $mergeObjects: [
                                                "$$edge.node",
                                                {
                                                  score: {
                                                    "$multiply": [
                                                      {
                                                        $cond: [
                                                          "$$edge.node.isWinner",
                                                          1.5,
                                                          1.2
                                                        ]
                                                      },
                                                      {
                                                        $first: {
                                                          $map: {
                                                            input: {
                                                              $filter: {
                                                                input: "$matchingEvents",
                                                                as: "matchedEvent",
                                                                cond: {
                                                                  $eq: [
                                                                    "$$matchedEvent.id",
                                                                    "$$edge.node.award.event.id"
                                                                  ]
                                                                }
                                                              }
                                                            },
                                                            as: "matched",
                                                            in: "$$matched.importance"
                                                          }
                                                        }
                                                      }
                                                    ]
                                                  }
                                                }
                                              ]
                                            }
                                          }
                                        }
                                      }
                                    }
                                  ]
                                }
                              }
                            ]
                          }
                        }
                      ]
                    }
                  }
                }
              }
            ]
          }
        }
      }
    }
  },
  {
    $unset: [
      "allEvents",
      "matchingEvents"
    ]
  }
])

Mongo Playground

我只想提一下,在保持建议的相同方法的同时,通过使用一些代码,可以使这一点更加清晰.先用distinct获得唯一的eventid.然后获取每个事件的匹配重要性.最后,使用arrayFilters执行一个查询,您可以使用此信息进行构造.

  • 最后一个方面不是提供的管道没有处理null个或缺失的值.因此,如果一个数组丢失,将抛出一个错误,因为$map希望输入是有效array.
{
    $map: {
        input: {$ifNull: ["$$this.credits",[]]}
    }
}

这也将用空[]替换null个值

Mongodb相关问答推荐

如何在Mongo Aggregate Query中创建集合的对象ID数组,并在列表中查找另一个集合中的ID

带dropTarget的MongoDB renameCollection命令是原子的吗

Spring数据MongoDB(聚合)

如何从集合中移除所有匹配的数组项?

mongoDB中数组中的聚合和元素

如何为具有相同名称的嵌套字段创建文本索引

Mongodb聚合中基于其他字段值的多个条件的动态新字段值

MongoDB:如何将所有文档合并到聚合管道中的单个文档中

如何在mongoDB中按嵌套文档分组( group by )

Spring Data + MongoDB GridFS 可以通过 Repository 访问吗?

增加嵌套对象中的值?

使用 Flask-pymongo 扩展通过 _id 在 MongoDB 中搜索文档

在 Heroku 上使用 Node 读取、写入和存储 JSON

MongoDB 的 BinData(0, "e8MEnzZoFyMmD7WSHdNrFJyEk8M=") 中的0是什么意思?

如何在 MongoDB 中进行内部连接?

如何在任意深度查找 MongoDB 字段名称

在 MongoDB 中按条件分组

无法从 MongoDb C# 中的 BsonType ObjectId 反序列化字符串

获取 mongodb 中所有唯一标签的列表

mongoose:按字母顺序排序