在 mongo 查询中,如何在数组中仅显示与过滤器匹配的元素?

in a mongo query, how to display in an array only the elements that match a filter?

这里是 table 个对象:

[
    {
        field0: value0,
        field1: value1,
        field2: {
            field3: value3,
            field4 : [
                { sfield1: svalue110, sfield2: svalue210 },
                { sfield1: svalue111, sfield2: svalue211 },
            ]
        }
    },
    {
        field0: value0,
        field1: value1,
        field2: {
            field3: value3,
            field4 : [
                { sfield1: svalue120, sfield2: svalue220 },
                { sfield1: svalue111, sfield2: svalue211 },
                { sfield1: svalue122, sfield2: svalue222 },
            ]
        }
    },
    {
        field0: value0,
        field1: value1,
        field2: {
            field3: value3,
            field4 : [
                { sfield1: svalue130, sfield2: svalue230 },
                { sfield1: svalue131, sfield2: svalue231 },
                { sfield1: svalue132, sfield2: svalue232 },
                { sfield1: svalue133, sfield2: svalue233 },
            ]
        }
    }
]

我想在 sfield1 和 sfield2 上应用过滤器,并仅显示 field4 的大小 > 0 的对象。在 field4 内,仅显示与过滤器匹配的对象。

例如,我只想显示 sfield1 = svalue111 和 sfield2 = svalue211 的对象

我必须得到这个结果:

[
    {
        field0: value0,
        field1: value1,
        field2: {
            field3: value3,
            field4 : [
                { sfield1: svalue111, sfield2: svalue211 },
            ]
        }
    },
    {
        field0: value0,
        field1: value1,
        field2: {
            field3: value3,
            field4 : [
                { sfield1: svalue111, sfield2: svalue211 },
            ]
        }
    }
]

我尝试了 addFields 并以这种方式减少:

{
    $addFields: {
        "field2.field4": {
            $reduce: {
                input: '$field2.field4',
                initialValue: [],
                in: {
                    $let: {
                        vars: {
                            ee: {
                                $filter: {
                                    input: '$$this.field4',
                                    as: 'z',
                                    cond: {
                                        $and: [
                                            {
                                                $eq: [
                                                    '$$z.sfield1',
                                                    "svalue111"
                                                ]
                                            },
                                            { $eq: ['$$z.sfield2', "svalue211"] }
                                        ]
                                    }
                                }
                            }
                        },
                        in: {
                            $cond: [
                                { $ne: [0, { $size: '$$ee' }] },
                                {
                                    $concatArrays: [
                                        '$$value',
                                        [
                                            {
                                                $mergeObjects: [
                                                    '$$this',
                                                    { "field2.field4": '$$ee' }
                                                ]
                                            }
                                        ]
                                    ]
                                },
                                '$$value'
                            ]
                        }
                    }
                }
            }
        }
    }
}

但是我有这个错误:

Error: command failed: {
    "ok" : 0,
    "errmsg" : "Invalid $addFields :: caused by :: FieldPath field names may not contain '.'.",
    "code" : 16412,
    "codeName" : "Location16412"
} : aggregate failed :....

感谢您的帮助

您可以在 $project 中使用 $filterfield4 数组中过滤掉。之后你会得到 field4: [] 那些过滤元素为 0 的。要删除这些可以使用 $match 来测试 $field4 是否在索引 0 处有一个元素(如果索引 0 处没有元素为空)。

db.collection.aggregate([
  {
    $project: {
      "field0": 1,  //show field0 in final result
      "field1": 1,  //show field1 in final result
      "field2.field3": 1,  //show field2.field3 in final result
      "_id": 0,     //hide _id in final result
      "field2.field4": {
        $filter: {
          input: "$field2.field4",
          as: "d",       //can put any alias here
          cond: {        //filtering condition
            $and: [
              {
                $eq: [
                  "$$d.sfield1",
                  "svalue111"
                ]
              },
              {
                $eq: [
                  "$$d.sfield2",
                  "svalue211"
                ]
              }
            ]
          }
        }
      }
    }
  },
  {
    "$match": {       //to remove the empty field4 array part 
      "field2.field4.0": {  //testing if field4 array has an element 
        "$exists": true
      }
    }
  }
])

demo

过滤子数组中元素的最佳方法是使用 $match$project 的聚合。

示例:

[{
  $match: { 
    field2.field4.sfield1: 'svalue1',
    field2.field4.sfield2: 'svalue2'
  }
}, {
  $project: {
    'field2.field4': {
      $filter: {
          input: '$field2.field4',
          as: 'item',
          cond: { $and: [
             {$eq: ["$$item.sfield1","svalue1"]},
             {$eq: ["$$item.sfield2","svalue2"]}
          ]}
      }
    }
  }
}]