我正在努力在投影阶段过滤nested数组。
实际的匹配条件比较复杂,但是这样就可以了:
db.collection.insertMany([
{ "id": 0,
"list_L1": [
{ "obj_L1": {
"list_L2": [
{id: "000", go: "Y"},
{id: "001", go: "N"},
{id: "002", go: "N"} ]}}]},
{ "id": 1,
"list_L1": [
{ "obj_L1": {
"list_L2": [
{id: "100", go: "Y"},
{id: "101", go: "Y"},
{id: "102", go: "N"} ]}}]},
{
"id": 2,
"list_L1": [
{ "obj_L1": {
"list_L2": [
{id: "200",go: "N"},
{id: "201",go: "N"},
{id: "202",go: "N"} ]}}]}
]);
db.collection.aggregate([
{$match: { "list_L1.obj_L1.list_L2.go": "Y"}}
]);
(如果格式很奇怪,请道歉 - 我正在努力节省垂直空间)
这个过滤器文档好吧,但我被要求也只保留
list_L2
的匹配元素,产生这样的东西:
[
{ "_id": ObjectId("5a934e000102030405000000"),
"id": 0,
"list_L1": [
{ "obj_L1": {
"list_L2": [
{id: "000", go: "Y"} ]}}},
{ "_id": ObjectId("5a934e000102030405000001"),
"id": 1,
"list_L1": [
{ "obj_L1": {
"list_L2": [
{id: "100", go: "Y"},
{id: "101", go: "Y"}} ]}}}
]
如果文档只有
list_L1
,那并不难,但我无法“看到”两层深度的值;这将返回空数组:
db.collection.aggregate([
{$match: { "list_L1.obj_L1.list_L2.go": "Y"}},
{$addFields: { "list_L1.obj_L1.list_L2": {
$filter: {
input: "$list_L1.obj_L1.list_L2",
cond: { $eq: ["$$this.go","Y"] }}}}}
]);
[
{
"_id": ObjectId("5a934e000102030405000000"),
"list_L1": [
{ "obj_L1": {
"list_L2": [] }}]},
{
"_id": ObjectId("5a934e000102030405000001"),
"list_L1": [
{
"obj_L1": {
"list_L2": [] }}]}
]
那么在匹配我想要的内容后如何过滤 inner 数组呢?或者,我可以删除所有文档的不匹配元素,然后过滤非空元素,但我对此太陌生了。
如果可能,重构您的架构。将最里面的数组元素存储为单独的文档将帮助您通过索引获得查询简单性和潜在的性能提升。
尽管如此,对于当前的场景,您可以使用
$map
来迭代 list_L1
数组。链接 $mergeObjects
和 $filter
仅返回 list_L2
中匹配的元素
db.collection.aggregate([
{
"$match": {
"list_L1.obj_L1.list_L2.go": "Y"
}
},
{
"$set": {
"list_L1": {
"$map": {
"input": "$list_L1",
"as": "ll1",
"in": {
"$mergeObjects": [
"$$ll1",
{
"obj_L1": {
"list_L2": {
"$filter": {
"input": "$$ll1.obj_L1.list_L2",
"as": "ll2",
"cond": {
"$eq": [
"Y",
"$$ll2.go"
]
}
}
}
}
}
]
}
}
}
}
}
])