zoukankan      html  css  js  c++  java
  • MongoDB查询内嵌数组(限定返回符合条件的数组中的数据)(1)

    https://blog.csdn.net/bicheng4769/article/details/79579830

    项目背景

    最近在项目中使用mongdb来保存压测结果中的监控数据,那么在获取监控数据时,遇到这样一个问题: 一个doucument中包含一个内嵌数组,其中内嵌数组也是分成好几类的数组(可以通过标识判断),那么我只需要返回特定的数组,而不是返回内嵌数组的所有数据。 
    原始数据:

    {
        "_id" : ObjectId("5aab3460353df3bd352e0e15"),
        "addTime" : ISODate("2018-03-16T03:05:04.363Z"),
        "tag" : "test",
        "userInfo" : [ 
            {
                "name" : "cj",
                "address" : "江苏",
                "age" : 24.0,
                "userTag" : "stu"
            }, 
            {
                "name" : "hj",
                "address" : "江苏",
                "age" : 26.0,
                "userTag" : "stu"
            }, 
            {
                "name" : "lbl",
                "address" : "美国",
                "age" : 22.0,
                "userTag" : "teach"
            }
        ]
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    查询条件是 tag =“test” userTag=”teach” 的学生的信息。期望返回的结果如下所示:

    {
        "_id" : ObjectId("5aab3460353df3bd352e0e15"),
        "userInfo" : [ 
            {
                "name" : "lbl",
                "address" : "美国",
                "age" : 22.0,
                "userTag" : "teach"
            }
        ]
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    但大多是find 的结果 是这样的

    db.test.find({"userInfo.userTag":"teach","tag":"test"})
    {
        "_id" : ObjectId("5aab3460353df3bd352e0e15"),
        "addTime" : ISODate("2018-03-16T03:05:04.363Z"),
        "tag" : "test",
        "userInfo" : [ 
            {
                "name" : "cj",
                "address" : "江苏",
                "age" : 24.0,
                "userTag" : "stu"
            }, 
            {
                "name" : "hj",
                "address" : "江苏",
                "age" : 26.0,
                "userTag" : "stu"
            }, 
            {
                "name" : "lbl",
                "address" : "美国",
                "age" : 22.0,
                "userTag" : "teach"
            }
        ]
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    $elemMatch 介绍

    其实我们在学习一个新的东西的时候,我建议是去官方文档查看一下,毕竟官方的才是最权威的。官方地址: 
    https://docs.mongodb.com/manual/reference/operator/projection/elemMatch/#proj._S_elemMatch
    我们可以看到 $elemMatch 是在projections方法下面,projections代表是限制返回字段的方法。 
    修改后的方法:

    db.test.find({"userInfo.userTag":"teach","tag":"test"},{"userInfo":{$elemMatch{"userTag":"teach"}}})
    • 1

    执行结果

    {
        "_id" : ObjectId("5aab3460353df3bd352e0e15"),
        "userInfo" : [ 
            {
                "name" : "lbl",
                "address" : "美国",
                "age" : 22.0,
                "userTag" : "teach"
            }
        ]
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    终于得到我想要的结果了 hhhhhhhhhhhhhhhhhhhhh。 
    然后我又想获取userInfo.userTag = “stu” 的数据,很简单啊

    db.test.find({"userInfo.userTag":"teach","tag":"test"},{"userInfo":{$elemMatch:{"userTag":"stu"}}})
    • 1

    但是结果出人意料:

    {
        "_id" : ObjectId("5aab3460353df3bd352e0e15"),
        "userInfo" : [ 
            {
                "name" : "cj",
                "address" : "江苏",
                "age" : 24.0,
                "userTag" : "stu"
            }
        ]
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    明明是2条stu的结果,为什么至返回一条呢? 其实$elemMatch 的定义 在官网中已经说过了,这是原话:

    The $elemMatch operator limits the contents of an <array> field from the query results to contain only the first element matching the $elemMatch condition.
    • 1

    注意 only the first element 也就是仅仅匹配第一个合适的元素。 
    那么 对于数组中只有一个返回元素,我们可以使用$elemMatch来查询,但是对于多个元素$elemMatch 是不适应。

    $Aggregation介绍

    文档地址:https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/

    1. $unwind: 
      https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/#pipe._S_unwind 
      大概意思就是将数组中的每一个元素转为每一条文档

    2. $match: 
      https://docs.mongodb.com/manual/reference/operator/aggregation/match/ 
      简单的过滤文档,条件查询。

    3. $project 
      https://docs.mongodb.com/manual/reference/operator/aggregation/project/ 
      修改输入文档的结构

    执行命令:

    db.test.aggregate([{"$unwind":"$userInfo"},
    {"$match":{"userInfo.userTag":"stu","tag":"test"}},
    {"$project":{"userInfo":1}}])
    • 1
    • 2
    • 3

    结果

    /* 1 */
    {
        "_id" : ObjectId("5aab3460353df3bd352e0e15"),
        "userInfo" : {
            "name" : "cj",
            "address" : "江苏",
            "age" : 24.0,
            "userTag" : "stu"
        }
    }
    
    /* 2 */
    {
        "_id" : ObjectId("5aab3460353df3bd352e0e15"),
        "userInfo" : {
            "name" : "hj",
            "address" : "江苏",
            "age" : 26.0,
            "userTag" : "stu"
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    这样的一个结果就是我们想要的。感兴趣的同学可以分别执行下这个三个操作(比较看看三个结果有什么不同),你就能理解 $unwind、$match、$project 三个方法的作用

    db.test.aggregate([{"$unwind":"$userInfo"}])
    db.test.aggregate([{"$unwind":"$userInfo"},{"$match":{"userInfo.userTag":"stu","tag":"test"}}])
    db.test.aggregate([{"$unwind":"$userInfo"},{"$match":{"userInfo.userTag":"stu","tag":"test"}},{"$project":{"userInfo":1}}])
    • 1
    • 2
    • 3

    总结

    1. 之前查询内嵌数组时,采用的方法是将整条document查询出来之后,在对内嵌数组进行代码过滤。只是觉得这种查询方式并没有用到mongodb的其他的一些方法,还是需求驱动学习。
    2. 学习一个新的东西建议从官方文档开始学习。

    结束语:

  • 相关阅读:
    Modelsim中观测代码覆盖率
    Allegro中Thermal relief Pad 和Anti Pad
    时序逻辑中阻塞赋值引起的仿真问题
    如何提高FPGA工作频率(转载)
    `include在Verilog中的应用
    forever
    wxpython 应用 使用 google gauth 认证
    sql to sqlalchemy 转换
    django 简易博客开发 5 markdown支持、代码高亮、gravatar头像服务
    simpletodo: 一个简易的 todo 程序 django版
  • 原文地址:https://www.cnblogs.com/bigben0123/p/9753327.html
Copyright © 2011-2022 走看看