【问题标题】:Searching value in 2 different fields mongodb + node.js在 2 个不同的字段中搜索值 mongodb + node.js
【发布时间】:2017-06-26 03:22:48
【问题描述】:

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

假设我的收藏是这样的;

{ 
    "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

为了找到键的出现,我写了两个不同的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
        }
    ]
}

【问题讨论】:

    标签: node.js mongodb mongodb-query aggregation-framework


    【解决方案1】:

    Mongo 3.4

    $match - 此阶段将保留所有school 数组和enrolledStudents,其中至少有一个与查询条件匹配的嵌入文档

    $group - 此阶段会将所有 schoolenrolledStudents 数组合并为一个组中每个 _id 的二维数组。

    $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"}}
    ])
    

    示例响应

    { "_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"}}
    

    示例响应

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

    您可以使用$redact 代替$groupmatch 并添加$project$map 来格式化响应。

    $redact 一次遍历一个文档级别并根据匹配条件执行$$DESCEND$$PRUNE

    唯一需要注意的是在id 的第一个文档级别中使用$ifNull,以便您可以将$$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"}}
    ])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-30
      • 1970-01-01
      • 2022-01-25
      • 2013-03-21
      相关资源
      最近更新 更多