我是新手。但是我尝试学习编写查询的最合乎逻辑的方法。

假设我有个收藏,如:

{
    "id" : NumberInt(1),
    "school" : [
        {
            "name" : "george",
            "code" : "01"
        },
        {
            "name" : "michelangelo",
            "code" : "01"
        }
    ],
    "enrolledStudents" : [
        {
            "userName" : "elisabeth",
            "code" : NumberInt(21)
        }
    ]
}
{
    "id" : NumberInt(2),
    "school" : [
        {
            "name" : "leonarda da vinci",
            "code" : "01"
        }
    ],
    "enrolledStudents" : [
        {
            "userName" : "michelangelo",
            "code" : NumberInt(25)
        }
    ]
}

我想列出一个key的出现及其相应的code值。

例如key:michelangelo
为了找到 key 的出现,我写了两个不同的aggregation查询:
db.test.aggregate([
    {$unwind: "$school"},
    {$match : {"school.name" : "michelangelo"}},
    {$project: {_id: "$id", "key" : "$school.name", "code" : "$school.code"}}
])


db.test.aggregate([
    {$unwind: "$enrolledStudents"},
    {$match : {"enrolledStudents.userName" : "michelangelo"}},
    {$project: {_id: "$id", "key" : "$enrolledStudents.userName", "code" : "$enrolledStudents.code"}}
])

这两个查询的结果返回我想要的;
{ "_id" : 1, "key" : "michelangelo", "code" : "01" }
{ "_id" : 2, "key" : "michelangelo", "code" : 25 }

其中一个要在enrolledStudents中搜索,另一个要在school字段中搜索。

可以将这两个查询简化为更具逻辑性的查询吗?还是这是唯一的方法?

ps:我知道数据库结构不是逻辑的,但是我尝试进行模拟。

编辑
我尝试用find编写查询。
db.test.find({$or: [{"enrolledStudents.userName" : "michelangelo"} , {"school.name" : "michelangelo"}]}).pretty()

但这将整个文档返回为:
{
    "id" : 1,
    "school" : [
        {
            "name" : "george",
            "code" : "01"
        },
        {
            "name" : "michelangelo",
            "code" : "01"
        }
    ],
    "enrolledStudents" : [
        {
            "userName" : "elisabeth",
            "code" : 21
        }
    ]
}
{
    "id" : 2,
    "school" : [
        {
            "name" : "leonarda da vinci",
            "code" : "01"
        }
    ],
    "enrolledStudents" : [
        {
            "userName" : "michelangelo",
            "code" : 25
        }
    ]
}

最佳答案

蒙戈3.4
$match-此阶段将保留所有school数组和enrolledStudents,其中至少有一个嵌入式文档与查询条件都匹配
$group-此阶段将组中每个school的所有enrolledStudents_id数组组合为2d数组。
$project-此阶段将对$filter数组进行merge,以匹配查询条件,并使用新标签$map数组对values进行匹配。
$unwind-此阶段将使数组变平。
$addFields$replaceRoot-此阶段将添加id字段,并将values数组提升到顶部。

db.collection.aggregate([
    {$match : {$or: [{"enrolledStudents.userName" : "michelangelo"} , {"school.name" : "michelangelo"}]}},
    {$group: {_id: "$id", merge : {$push:{$setUnion:["$school", "$enrolledStudents"]}}}},
    {$project: {
        values: {
              $map:
                 {
                   input: {
                            $filter: {
                                input: {"$arrayElemAt":["$merge",0]},
                                as: "onef",
                                cond: {
                                    $or: [{
                                        $eq: ["$$onef.userName", "michelangelo"]
                                    }, {
                                        $eq: ["$$onef.name", "michelangelo"]
                                    }]
                                }
                            }
                        },
                   as: "onem",
                   in: {
                         key : { $ifNull: [ "$$onem.userName", "$$onem.name" ] },
                         code : "$$onem.code"}
                 }
            }
        }
    },
    {$unwind: "$values"},
    {$addFields:{"values.id":"$_id"}},
    {$replaceRoot: { newRoot:"$values"}}
])

sample 响应
{ "_id" : 2, "key" : "michelangelo", "code" : 25 }
{ "_id" : 1, "key" : "michelangelo", "code" : "01" }

Mongo

$project替换上述聚合的最后两个阶段,以格式化响应。
{$project: {"_id": 0 , id:"$_id", key:"$values.key", code:"$values.code"}}

sample 响应
{ "_id" : 2, "key" : "michelangelo", "code" : 25 }
{ "_id" : 1, "key" : "michelangelo", "code" : "01" }

您可以使用$redact代替$groupmatch,并添加$project$map来格式化响应。
$redact一次遍历文档级别,并根据匹配条件执行$$DESCEND$$PRUNE

唯一需要注意的是在$ifNull的第一个文档级别使用id,以便您可以将$$DESCEND扩展到嵌入式文档级别以进行进一步处理。
db.collection.aggregate([
    {
        $redact: {
            $cond: [{
                $or: [{
                    $eq: ["$userName", "michelangelo"]
                }, {
                    $eq: ["$name", "michelangelo"]
                }, {
                    $ifNull: ["$id", false]
                }]
            }, "$$DESCEND", "$$PRUNE"]
        }
    },
    {
        $project: {
            id:1,
            values: {
              $map:
                 {
                   input: {$setUnion:["$school", "$enrolledStudents"]},
                   as: "onem",
                   in: {
                         key : { $ifNull: [ "$$onem.userName", "$$onem.name" ] },
                         code : "$$onem.code"}
                 }
            }
        }
    },
    {$unwind: "$values"},
    {$project: {_id:0,id:"$id", key:"$values.key", code:"$values.code"}}
])

10-04 21:29