0

MongoDB新手在这里。

我有一个看起来像这样的“客户”文档:

{
  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。我希望返回changeLogs给定环境的列表,只有environment._id继续。

我可以client使用这个找到正确的文档_id

db.clients.find({'products.environments._id': ObjectId("5a1bf4b410842200043d56ff")})

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

假设我有_idfirst environmentof the first product,我想要的输出如下:

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

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

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

4

3 回答 3

1

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

请注意,我正在使用您提供的示例文档中的“环境”的“名称”字段。“名称”可以根据需要替换为“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" } ] }
于 2019-11-19T02:42:02.207 回答
1

这里的想法是$unwind产品数组,以便它的环境可以作为输入提供$filter给.$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"
    }
  }
]

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

于 2019-11-18T20:23:48.670 回答
0
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" }
  ]
}

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

于 2019-11-19T09:50:28.130 回答