我有这样的收藏
[
{
"_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文档,但未找到任何内容。
有人有什么解决办法吗?
答案 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"
}
}
}
}
]);