MongoDB/Mongoose 如何 return 通过 _id 嵌套子文档

MongoDB/Mongoose how to return a nested subdocument by _id

MongoDB这里是新手

我有一个 'client' 文档,如下所示:

{
  name: "myClient",
  products: [{
    name: "myProduct1",
    environments: [{
        name: "myEnvironment1",
        changeLogs: [
          { "some": "fields21" },
          { "some": "fields22" }
        ]
      },
      {
        name: "myEnvironment2",
        changeLogs: [
          { "some": "fields11" },
          { "some": "fields12" }
        ]
      }
    ]
  },
  {
    name: "myProduct2",
    environments: [{
        name: "myEnv1",
        changeLogs: [
          { "some": "fields1" },
          { "some": "fields2" }
        ]
      },
      {
        name: "myEnv1",
        changeLogs: [
          { "some": "fields3" },
          { "some": "fields4" }
        ]
      }
    ]
  }]
}

所以一个客户有很多products,有很多environments,有很多changeLogs。我正在寻找 return 给定环境的 changeLogs 列表,只有 environment._id 可以继续。

我可以使用 _id:

找到正确的 client 文档
db.clients.find({'products.environments._id': ObjectId("5a1bf4b410842200043d56ff")})

但这 return 是整个 client 文档。我想要的是 return 只是环境中的 changeLogs 数组 _id: ObjectId("5a1bf4b410842200043d56ff")

假设我有第一个product的第一个environment_id,我想要的输出如下:

[
  { "some": "fields21" },
  { "some": "fields22" }
]

您建议我使用什么查询来实现此目的?

非常感谢您的帮助。到目前为止的文档只是令人困惑,但我相信我最终会到达那里!

这里的思路是$unwind the products array so that its environments can be fed as input to $filter after a $match_id

(假设环境 _id 为 1)

db.collection.aggregate([
  {
    $unwind: "$products"
  },
  {
    $match: {
      "products.environments._id": 1
    }
  },
  {
    $project: {
      "logsArray": {
        $filter: {
          input: "$products.environments",
          as: "env",
          cond: {
            $eq: [
              "$$env._id",
              1
            ]
          }
        }
      }
    }
  },
  {
    $unwind: "$logsArray"
  }
])

O/P 应该是这样的:

[
  {
    "_id": ObjectId("5a934e000102030405000000"),
    "logsArray": {
      "changeLogs": [
        {
          "some": "fields21"
        },
        {
          "some": "fields22"
        }
      ],
      "id": 1,
      "name": "myEnvironment1"
    }
  }
]

注意: 注意 logsArray 的最后阶段 $unwind,我认为这只是漂亮的输出。否则没有它,结果也是可以接受的(如果你同意,可以删除它)。

这只是进行聚合查询的另一种方式。这样就得到了想要的结果。

请注意,我使用的是您提供的示例文档中 "environments" 的 "name" 字段。 "name" 可以根据需要替换为 "id"。

var ENV = "myEnvironment1";

db.env.aggregate( [
  { $match: { 
  { $unwind: "$products" },
  { $unwind: "$products.environments" },
  { $match: { "products.environments.name": ENV} },
  { $project: { _id: 0, changeLogs: "$products.environments.changeLogs" } },
] )

结果:

{ "changeLogs" : [ { "some" : "fields21" }, { "some" : "fields22" } ] }

如果变量ENV的值改变了,那么结果也会相应;例如:ENV = "myEnv1";

{ "changeLogs" : [ { "some" : "fields1" }, { "some" : "fields2" } ] }
{ "changeLogs" : [ { "some" : "fields3" }, { "some" : "fields4" } ] }
db.clients.aggregate([
  {
    $unwind: "$products"
  },
  {
    $unwind: "$products.environments" 
  },
  {
    $match: { "products.environments._id": ObjectId("5a1bf4b410842200043fffff") }
  },
  {
    $project: { _id: 0, changeLogs: "$products.environments.changeLogs" }
  }
]).pretty()

结果:

{
  "changeLogs": [
    { "some": "fields21" },
    { "some": "fields22" }
  ]
}

对于那些发现代码令人困惑的人,我发现一次只添加一个聚合方法非常有用,查看结果,然后将下一个方法添加到管道中。管道完成后,我还尝试删除中间步骤,看看是否可以用更少的管道获得相同的结果。