• MongoDB查询内嵌数组(限定返回符合条件的数组中的数据)(1)


    原文地址:https://blog.csdn.net/bicheng4769/article/details/79579830

    项目背景

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

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

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

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

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

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

    $elemMatch 介绍

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

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

    执行结果

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

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

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

    但是结果出人意料:

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

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

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

    注意 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/ 
      修改输入文档的结构

    执行命令:

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

    结果

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

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

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

    总结

    1. 之前查询内嵌数组时,采用的方法是将整条document查询出来之后,在对内嵌数组进行代码过滤。只是觉得这种查询方式并没有用到mongodb的其他的一些方法,还是需求驱动学习。
    2. 学习一个新的东西建议从官方文档开始学习。
  • 相关阅读:
    leetcode简单刷题
    pycharm常用快捷键
    pycharm之black配置for python file(代码格式化工具)
    appium
    scheduleAtFixedRate 和 timer 执行对比
    Java 线程池创建的四种方式
    java 数据库连接池和普通连接 对比
    java 线程池 实现
    java 定时任务 Timer 范例
    java加载properties配置文件的几种方法
  • 原文地址:https://www.cnblogs.com/phpk/p/10937504.html
Copyright © 2020-2023  润新知