这是如何在投影阶段过滤嵌套数组?的后续内容。
在使用
$match
找到相关文档后,我被要求仅输出数组深处的一些元素(在匹配条件中使用)。有一个数组-对象-数组-对象-数组层次结构:
db.collection.insertMany([
{ "person": [
{ "name": "joe",
"empl": [
{ "name": "joe_e0",
"job": [
{ "id": "joe_e0_j0", "go": "Y" },
{ "id": "joe_e0_j1", "go": "N" } ]}]}]},
{ "person": [
{ "name": "amy",
"empl": [
{ "name": "amy_e0",
"job": [
{ "id": "amy_e0_j0", "go": "Y" },
{ "id": "amy_e0_j1", "go": "N" } ]}]}]},
{ "person": [
{ "name": "tom",
"empl": [
{ "name": "tom_e0",
"job": [
{ "id": "tom_e0_j0", "go": "N" },
{ "id": "tom_e0_j1", "go": "N" },
{ "id": "tom_e0_j2", "go": "N" } ]}]}]}
]);
db.collection.aggregate([
{ "$match": {"person.empl.job.go": "Y"} },
{
$set: {
person: {
$map: {
input: "$person",
as: "p",
in: {
$mergeObjects: [
"$$p",
{
"empl": {
$map: {
input: "$$p.empl",
as: "e",
in: {
$mergeObjects: [
"$$e",
{
"job": {
$filter: {
input: "$$e.job",
as: "j",
cond: { $eq: ["$$j.go","Y"] }
}
}}]}}} // empl
}]}}} // person
}}
]);
这会产生我想要的输出,带来原始对象和过滤
person.empl.job
:
[
{ "_id": ObjectId("5a934e000102030405000000"),
"dept": "d0",
"person": [
{ "empl": [
{ "job": [
{ "go": "Y", "id": "joe_e0_j0" }],
"name": "joe_e0" }],
"name": "joe" }]},
{ "_id": ObjectId("5a934e000102030405000001"),
"dept": "d1",
"person": [
{ "empl": [
{ "job": [
{ "go": "Y", "id": "amy_e0_j0" }],
"name": "amy_e0"}],
"name": "amy" }]}
]
但是,
$map
和 $mergeObjects
来下降这个对象并保留除过滤数组之外的所有内容吗?有没有更简单/更有效的方法?person.empl.job
的实际情况要复杂得多,我必须在$match
和稍后的$filter
中说明。有没有办法避免这种情况?根据您将使用此聚合的上下文/语言,您应该能够将两次使用的条件放入变量中,以提高可读性并在匹配和过滤器中重用它。 更重要的是,还有另一种方法可以做到这一点,即使用 $redact 阶段。 它更具可读性,但我没有对此进行性能分析。
这是您的案例的代码:
db.collection.aggregate([
{
"$match": {
"person.empl.job.go": "Y"
}
},
{
$redact: {
$cond: {
if: {
$or: [
{
$ne: [
"$person",
undefined
]
},
{
$ne: [
"$name",
undefined
]
},
{
$eq: [
"$go",
"Y"
]
}
]
},
then: "$$DESCEND",
else: "$$PRUNE"
}
}
}
])
$person 和 $name 上的条件仅用于下降到对象级别。
希望有帮助