在聚合中合并深度嵌套的数组

问题描述 投票:0回答:1

这是如何在投影阶段过滤嵌套数组?的后续内容。

在使用

$match
找到相关文档后,我被要求仅输出数组深处的一些元素(在匹配条件中使用)。有一个数组-对象-数组-对象-数组层次结构:

db.collection.insertMany([
  { "person": [
      { "name": "joe",
        "empl": [
          { "name": "joe_e0",
            "job": [
              { "id": "joe_e0_j0", "go": "Y" },
              { "id": "joe_e0_j1", "go": "N" } ]}]}]},
  { "person": [
      { "name": "amy",
        "empl": [
          { "name": "amy_e0",
            "job": [
              { "id": "amy_e0_j0", "go": "Y" },
              { "id": "amy_e0_j1", "go": "N" } ]}]}]},
  { "person": [
      { "name": "tom",
        "empl": [
          { "name": "tom_e0",
            "job": [
              { "id": "tom_e0_j0", "go": "N" },
              { "id": "tom_e0_j1", "go": "N" },
              { "id": "tom_e0_j2", "go": "N" } ]}]}]}
]);

db.collection.aggregate([
  { "$match": {"person.empl.job.go": "Y"} },
  {
    $set: {
      person: {
        $map: {
          input: "$person",
          as: "p",
          in: {
            $mergeObjects: [
              "$$p",
              {
                "empl": {
                  $map: {
                    input: "$$p.empl",
                    as: "e",
                    in: {
                      $mergeObjects: [
                        "$$e",
                        {
                          "job": {
                            $filter: {
                              input: "$$e.job",
                              as: "j",
                              cond: { $eq: ["$$j.go","Y"] }
                            }
                          }}]}}} // empl
              }]}}} // person
  }}
]);

这会产生我想要的输出,带来原始对象过滤

person.empl.job

[
  { "_id": ObjectId("5a934e000102030405000000"),
    "dept": "d0",
    "person": [
      { "empl": [
          { "job": [
              { "go": "Y", "id": "joe_e0_j0" }],
            "name": "joe_e0" }],
        "name": "joe" }]},
  { "_id": ObjectId("5a934e000102030405000001"),
    "dept": "d1",
    "person": [
      { "empl": [
          { "job": [
              { "go": "Y", "id": "amy_e0_j0" }],
            "name": "amy_e0"}],
        "name": "amy" }]}
]

Mongo 游乐场

但是,

  • 我真的需要交替使用
    $map
    $mergeObjects
    来下降这个对象并保留除过滤数组之外的所有内容吗?有没有更简单/更有效的方法?
  • person.empl.job
    的实际情况要复杂得多,我必须在
    $match
    和稍后的
    $filter
    中说明。有没有办法避免这种情况?
mongodb aggregation-framework
1个回答
0
投票

根据您将使用此聚合的上下文/语言,您应该能够将两次使用的条件放入变量中,以提高可读性并在匹配和过滤器中重用它。 更重要的是,还有另一种方法可以做到这一点,即使用 $redact 阶段。 它更具可读性,但我没有对此进行性能分析。

这是您的案例的代码:

db.collection.aggregate([
  {
    "$match": {
      "person.empl.job.go": "Y"
    }
  },
  {
    $redact: {
      $cond: {
        if: {
          $or: [
            {
              $ne: [
                "$person",
                undefined
              ]
            },
            {
              $ne: [
                "$name",
                undefined
              ]
            },
            {
              $eq: [
                "$go",
                "Y"
              ]
            }
          ]
        },
        then: "$$DESCEND",
        else: "$$PRUNE"
      }
    }
  }
])

$person 和 $name 上的条件仅用于下降到对象级别。

在此处查看实际操作

希望有帮助

© www.soinside.com 2019 - 2024. All rights reserved.