有没有办法过滤mongodb中的嵌入式数组?

时间:2019-11-25 15:06:47

标签: mongodb mongodb-query

我有这样的收藏

[
{
    "_id" : {
        "id" : 1
    },
    "group" : [ 
        {
            "id" : 1,
            "users" : [ 
                {
                    "id" : 3000,
                    "active" : true,
                }, 
                {
                    "id" : 3001,
                    "active" : false,
                }
            ]
        },
    ]
},
{
    "_id" : {
        "id" : 2
    },
    "group" : [ 
        {
            "id" : 2,
            "users" : [ 
                {
                    "id" : 4000,
                    "active" : true,
                }, 
                {
                    "id" : 4001,
                    "active" : false,
                }
            ]
        },
    ]
}
]

我想投影所有集合,但是仅活动等于true的用户。像这样:

[
{
    "_id" : {
        "id" : 1
    },
    "group" : [ 
        {
            "id" : 1,
            "users" : [ 
                {
                    "id" : 3000,
                    "active" : true,
                }, 
            ]
        },
    ]
},
{
    "_id" : {
        "id" : 2
    },
    "group" : [ 
        {
            "id" : 2,
            "users" : [ 
                {
                    "id" : 4000,
                    "active" : true,
                }, 
            ]
        },
    ]
}
]

我试图用它带来结果,但是不起作用。

{
        $project: {

            '_id': 1,
            'groups': {
                 $filter: {
                    input: '$group',
                    as: 'g',
                    cond: {
                        $and: [
                            { '$eq': ['$$g.users.active', true] }
                        ],
                    },
                },
            }
        }
}

如果我只使用{ '$eq': ['$$g.id', 1] },它可以工作,但是当我尝试使用第三级时,这是行不通的。

是否有某种方法可以访问第三级并使用值进行过滤?我搜索了mongodb文档,但未找到任何内容。

有人有什么解决办法吗?

3 个答案:

答案 0 :(得分:3)

每个嵌套级别必须使用$map。此外,您需要$mergeObjects提取属于group且未过滤的所有属性。

[{ 
    $project: { 
        '_id': 1,
        'group': { 
            $map: { 
                'input': '$group',
                'as': 'g',
                'in': {
                    $mergeObjects: [
                        '$$g', 
                        {
                            'users': {
                                $filter: { 
                                    "input": "$$g.users",
                                    "as": "u",
                                    "cond": { 
                                        $and: [{'$eq': ['$$u.active', true]}]
                                    }
                                }
                            }
                        }
                    ]
                }
            }
        }
    }
}]

建议的聚合返回您需要的所有内容并应用请求的过滤器。多亏了$mergeObjects,我不仅能够提取group.users数组,还可以提取group数组(group._id)内的其他所有内容。

答案 1 :(得分:3)

我相信该管道将产生所需的输出:

db.foo.aggregate([
{$addFields: {group: {$map: {   // "overwrite" group with addFields
                input: "$group",
                as: "z",
                in: {
                    id: "$$z.id",   // just copy the inbound _id 
                    users: {$filter: {
                            input: "$$z.users",
                            as: "zz",
                            cond: {$eq: [ "$$zz.active", true] }
                        }}
                }

            }}
    }}
                      ]);

答案 2 :(得分:1)

添加另一种方法来实现目标O / P。

这里的想法是首先$unwind是外部数组字段group,因此在$filter处馈送group.users,以分块活动用户。然后,$group再次使用_id,并使用$push

修改group的结构
db.collection.aggregate([
  {
    $unwind: "$group"
  },
  {
    $addFields: {
      filteredUsers: {
        $filter: {
          input: "$group.users",
          as: "u",
          cond: {
            $eq: ["$$u.active", true]
          }
        }
      }
    }
  },
  {
    $group: {
      _id: "$_id",
      group: {
        $push: {
          id: "$group.id",
          users: "$filteredUsers"
        }
      }
    }
  }
]);