如何为两层深的数组过滤数组元素?

How to Filter Array Elements for Arrays Two Levels Deep?

在我的collection里面有一个数组,里面有objects,里面有数组。我的数据如下所示:

{
  'settings': {
    'labourContributions': [
      {
        'show': True,
        'Accrual': True,
        '_id': ObjectId('abc'),
        'name': 'Holidays',
        'amount': 10,
        'target': [
          {
            'date': 2021-05-17T23: 00: 00.000+00: 00,
            'percent': 4.0
          },
          {
            'date': 2021-05-19T23: 00: 00.000+00: 00,
            'percent': 10.0
          }
        ]
      },
      {
        'show': True,
        'Accrual': True,
        '_id': ObjectId('abd'),
        'name': 'Taxes',
        'amount': 10,
        'target': [
          {
            'date': 2021-04-01T23: 00: 00.000+00: 00,
            'percent': 8.0
          },
          {
            'date': 2021-05-27T23: 00: 00.000+00: 00,
            'percent': 10.0
          }
        ]
      }
    ]
  }
}

我的目标是 return 根据一些匹配 labourContributions 的所有元素,但在 labourContributions.target 内我只想要一个元素,根据其他一些匹配(假设 percent > 5).

尝试使用聚合管道进行此操作我目前只能得到:

c = collection.aggregate([
  {
    "$match": {
      "settings.labourContributions": {
        "$elemMatch": {
          "Accrual": True
        }
      }
    }
  },
  {
    "$project": {
      "settings.labourContributions.$.target": {
        "$filter": {
          "input": "$settings.labourContributions.$.target",
          "as": "contributions",
          "cond": {
            "$gt": [
              "$$contributions.percent",
              5
            ]
          }
        }
      }
    }
  }
])

我不认为 $project 阶段可以支持 $ 数组切片。如何根据更深的数组进行查询?

I don't think the $project stage can support $ slices of arrays. How can I query based on my deeper array?

您只能在更新查询中使用 $ 个位置,

  • $match 你的两个条件都使用嵌套 $elemMatch
  • $filter 迭代 labourContributions 的循环并按 Accrual 条件
  • 过滤主要文档
  • $map 迭代上述过滤文档的循环
  • $filter 迭代 target 数组的循环并按 percent
  • 过滤文档
  • $mergeObjects 合并地图的当前对象和过滤后的 target 数组
c = collection.aggregate([
  {
    $match: {
      "settings.labourContributions": {
        $elemMatch: {
          Accrual: true,
          target: {
            $elemMatch: {
              percent: { $gt: 5 }
            }
          }
        }
      }
    }
  },
  {
    $project: {
      "settings.labourContributions": {
        $map: {
          input: {
            $filter: {
              input: "$settings.labourContributions",
              cond: { $eq: ["$$this.Accrual", true] }
            }
          },
          in: {
            $mergeObjects: [
              "$$this",
              {
                target: {
                  $filter: {
                    input: "$$this.target",
                    cond: { $gt: ["$$this.percent", 5] }
                  }
                }
              }
            ]
          }
        }
      }
    }
  }
])

Playground