Mongodb-从数组,匹配项属性或子数组项属性聚合项

时间:2019-04-09 18:05:04

标签: mongodb aggregation-framework

我的文档具有以下结构:

{
  _id: "UNIQUE_ID",
  myarray: [
    {
      mykey: '12345',
      // other fields
    },
    {
      // other fields
      nestedarray: [
        {
          mykey: '67890',
          // other fields
        }
      ]
    }
  ]
}

我需要返回myarray(在mykeymyarray上属于一组值的nestedarray上的所有项目。例如,对于上面的文档,如果一组值是['12345, '67890'],则应返回myarray中的两个项目。

我正在使用以下代码来做到这一点:

collection.aggregate([
  {
    $match: {
      "_id": documentId,
      $or: [
        { "myarray": {$elemMatch: {"mykey": { $in: ['12345, '67890'] } } } },
        { "myarray.$.nestedarray": {$elemMatch: {"mykey": { $in: ['12345, '67890'] } }} }
      ]
    }
  },
  {
    $project: {
      myarray: {
        $filter: {
          input: '$myarray',
          as: 'arrayitem',
          cond: {
            $or: [
              { $eq: ["$$arrayitem.mykey", '12345'] },
              { $eq: ["$$arrayitem.nestedarray.[$].mykey", '12345'] }
            ]
          }
        }
      }
    }
  }
]);

但这只会返回mykey级别在myarray上匹配的项(在nestedarray内部不匹配)。

我在做什么错了?

此外,如何在$ filter函数中使用集合['12345, '67890']而不是单个值'12345'

澄清:

  • 如果mykey上的某个项目上有myarray个匹配项,则包括该项目(此项目将没有nestedarray字段)
  • 如果mykey上的项与nestedarray相匹配:包括myarray中的项,其中包含nestedarray(还包含nestedarray的全部内容)。 myarray中的此项将没有mykey字段

示例:

数据:

{
  _id: "UNIQUE_ID",
  myarray: [
    {
      mykey: '11111',
      // other fields
    },
    {
      // other fields
      nestedarray: [
        {
          mykey: '22222',
          // other fields
        },
        {
          mykey: '84325',
          // other fields
        }
      ]
    },
    {
      mykey: '645644',
      // other fields
    },
    {
      // other fields
      nestedarray: [
        {
          mykey: '23242',
          // other fields
        },
        {
          mykey: '23433',
          // other fields
        }
      ]
    }
  ]
}

一组值:['11111', '22222']

预期的查询结果:

{
  _id: "UNIQUE_ID",
  myarray: [
    {
      mykey: '11111',
      // other fields
    },
    {
      // other fields
      nestedarray: [
        {
          mykey: '22222',
          // other fields
        },
        {
          mykey: '84325',
          // other fields
        }
      ]
    }
  ]
}

2 个答案:

答案 0 :(得分:2)

您可以使用以下汇总

db.collection.aggregate([
  { "$match": { "_id": documentId }},
  { "$project": {
    "myarray": {
      "$filter": {
        "input": {
          "$map": {
            "input": "$myarray",
            "as": "arrayitem",
            "in": {
              "mykey": "$$arrayitem.mykey",
              "nestedarray": "$$arrayitem.nestedarray",
              "aaaa": {
                "$filter": {
                  "input": "$$arrayitem.nestedarray",
                  "as": "vv",
                  "cond": { "$in": ["$$vv.mykey", ["12345", "67890"]] }
                }
              }
            }
          }
        },
        "as": "ff",
        "cond": {
          "$or": [
            { "$in": ["$$ff.mykey", ["12345", "67890"]] },
            { "$gte": [{ "$size": { "$ifNull": ["$$ff.aaaa", []] }}, 1] }
          ]
        }
      }
    }
  }},
  { "$project": { "myarray.aaaa": 0 }}
])

这是工作中的example

答案 1 :(得分:2)

您可以使用单个$filter,然后以cond的身份直接检查mykey或将$anyElementTrue用于数组。

db.col.aggregate([
    {
        $project: {
            myarray: {
                $filter: {
                    input: "$myarray",
                    cond: {
                        $or: [
                            { $in: [ "$$this.mykey", ["11111", "22222"] ] },
                            { $anyElementTrue: [ 
                                { 
                                    $map: { 
                                        input: { $ifNull: [ "$$this.nestedarray", [] ] }, 
                                        as: "na", 
                                        in: { $in: [ "$$na.mykey", ["11111", "22222"] ] } 
                                    } 
                                } 
                                ] 
                            }
                        ]
                    }
                }
            }
        }
    }
])

Mongo playground