MongoDB实战篇:高级查询----$elemMatch与aggregate

来都来了 2018-04-03 16:42:00 ⋅ 573 阅读

基本的Find查询将在其他章节示例,本文主要针对于遇到的问题与解决的方法做个记录,希望可以减少遇到这类问题的同胞-_-!

第一部分 需求与问题

1.1 数据结构

1.1.1 插入测试数据
db.hhw.insert({results: [ 
{ item: "a", qty: 26, tags: ["blank", "red"], dim_cm: [ 1, 10 ] },
{ item: "a", qty: 27, tags: ["blank", "red"], dim_cm: [ 15, 30 ] },
{ item: "a", qty: 28, tags: ["blank", "red"], dim_cm: [ 50, 70 ] },
{ item: "b", qty: 27, tags: ["blank", "red"], dim_cm: [ 80, 90 ] }
]
});
1.1.2 获取数据, 在此没有➕pretty()格式化
> db.hhw.find()
{ "_id" : ObjectId("58b675a556341c2186667dd4"), 
"results" : [ { "item" : "a", "qty" : 26, "tags" : [ "blank", "red" ], "dim_cm" : [ 1, 10 ] },
{ "item" : "a", "qty" : 27, "tags" : [ "blank", "red" ], "dim_cm" : [ 15, 30 ] },
{ "item" : "a", "qty" : 28, "tags" : [ "blank", "red" ], "dim_cm" : [ 50, 70 ] },
{ "item" : "b", "qty" : 27, "tags" : [ "blank", "red" ], "dim_cm" : [ 80, 90 ] } ] }

1.2 需求

需求一: 获取到resultsitem的值为a的结果集合.

第二部分 解决问题

2.1 尝试的方法一 -------- find子句$elemMatch

参考官网V3.4 eleMatch, 大致功能为投影操作符将限制查询返回的数组字段的内容只包含匹配elemMatch条件的数组元素。其实`$elemMatch专门用于查询数组Field中元素是否满足指定的条件。

> db.hhw.find({ 
results: { $elemMatch: { item: "a"}}})
#确实是全部数据
{ "_id" : ObjectId("58b675a556341c2186667dd4"),
 "results" : [ { "item" : "a", "qty" : 26, "tags" : [ "blank", "red" ], "dim_cm" : [ 1, 10 ] },
 { "item" : "a", "qty" : 27, "tags" : [ "blank", "red" ], "dim_cm" : [ 15, 30 ] },
 { "item" : "a", "qty" : 28, "tags" : [ "blank", "red" ], "dim_cm" : [ 50, 70 ] },
  { "item" : "b", "qty" : 27, "tags" : [ "blank", "red" ], "dim_cm" : [ 80, 90 ] } ] }

按照官网V3.4 eleMatch的实例,一直达不到预期的效果,按照的版本是v3.4.0, 文档参考的也是v3.4.0好奇!
解决的方法,参考了StackOverflow中, find之后的第一个参数设置为{}, 但是得写上.

> db.hhw.find({}, { 
 results: {
   $elemMatch: { item: "a"}
   }
 })
 #只返回了符合elemMatch的第一条数据
{ "_id" : ObjectId("58b675a556341c2186667dd4"),
 "results" : [ { "item" : "a", "qty" : 26, "tags" : [ "blank", "red" ], "dim_cm" : [ 1, 10 ] } ] }

注意:

1. 数组中元素是内嵌文档。
2. 如果多个元素匹配$elemMatch条件,操作符返回数组中第一个匹配条件的元素。

2.2 既然来了, 就操作一下$elemMatch吧

需求: 要查询 dim_cm 中满足至少存在一个元素大于等于10且小于20的

2.3 转到第三部分

第三部分 聚合aggregate

3.1 语法以及参数

>db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
>$project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
$match:用于过滤数据,只输出符合条件的文档。
$match使用MongoDB的标准查询操作。
$limit:用来限制MongoDB聚合管道返回的文档数。
$skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
$unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
$group:将集合中的文档分组,可用于统计结果。
$sort:将输入文档排序后输出。
$geoNear:输出接近某一地理位置的有序文档。

参数太多,还是直接来上代码

*还是原来的问题,在此使用aggregate来解决

3.2代码如下

> db.hhw.aggregate(
    {"$unwind": "$results"},
    {"$match": {"results.item": "a"}},
    {"$group":{        "_id":"$_id",        "myResult":{            "$push": "$results"
        }
      }}
)#结果达到预期效果,三个a
{ "_id" : ObjectId("58b675a556341c2186667dd4"), "myResult" : [ { "item" : "a", "qty" : 26, "tags" : [ "blank", "red" ], "dim_cm" : [ 1, 10 ] }, { "item" : "a", "qty" : 27, "tags" : [ "blank", "red" ], "dim_cm" : [ 15, 30 ] }, { "item" : "a", "qty" : 28, "tags" : [ "blank", "red" ], "dim_cm" : [ 50, 70 ] } ] }

3.3 接下来一步步拆分上边的三条语句

3.3.1 $unwind: 将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。类似于遍历,前后都有$符号
> db.hhw.aggregate({"$unwind": "$results"})

{ "_id" : ObjectId("58b675a556341c2186667dd4"), "results" : { "item" : "a", "qty" : 26, "tags" : [ "blank", "red" ], "dim_cm" : [ 1, 10 ] } }
{ "_id" : ObjectId("58b675a556341c2186667dd4"), "results" : { "item" : "a", "qty" : 27, "tags" : [ "blank", "red" ], "dim_cm" : [ 15, 30 ] } }
{ "_id" : ObjectId("58b675a556341c2186667dd4"), "results" : { "item" : "a", "qty" : 28, "tags" : [ "blank", "red" ], "dim_cm" : [ 50, 70 ] } }
{ "_id" : ObjectId("58b675a556341c2186667dd4"), "results" : { "item" : "b", "qty" : 27, "tags" : [ "blank", "red" ], "dim_cm" : [ 80, 90 ] } }
3.3.3 $match过滤数据
3.3.4 $group将集合中的文档分组,可用于统计结果

上边的例子我们将所有的字段统一返回, 假如此时我们只想返回item tags呢?

> db.hhw.aggregate(
    {"$unwind": "$results"},
    {"$match": {"results.item": "a"}},
    {"$group":{        "_id":"$_id",        "myResult":{            "$push": {"Item": "$results.item", "tags": "$results.tags"}
        }
      }}
)

{ "_id" : ObjectId("58b675a556341c2186667dd4"), "myResult" : 
[ { "Item" : "a", "tags" : [ "blank", "red" ] }, 
{ "Item" : "a", "tags" : [ "blank", "red" ] },
{ "Item" : "a", "tags" : [ "blank", "red" ] } 
] }
3.3.5 $project 限定结果集合

此时只有两个字段(_id, results), 只显示results

db.hhw.aggregate(
    { $project : {
        _id : 0 ,
        results : 1 ,
    }}
 );
 
{ "results" : [ { "item" : "a", "qty" : 26, "tags" : [ "blank", "red" ], "dim_cm" : [ 1, 10 ] }, { "item" : "a", "qty" : 27, "tags" : [ "blank", "red" ], "dim_cm" : [ 15, 30 ] }, { "item" : "a", "qty" : 28, "tags" : [ "blank", "red" ], "dim_cm" : [ 50, 70 ] }, { "item" : "b", "qty" : 27, "tags" : [ "blank", "red" ], "dim_cm" : [ 80, 90 ] } ] }

遇到的问题

X.1 在mongoose 中aggregate中match id 时出现错误的解决办法:

Product.aggregate(
    {"$unwind": "$products"},
 // 执行成功
    {"$match": {"products.price": 9}},
 // 执行失败
    {"$match": {"products._id": "58b77e509219010a6eac48ed"}},#下边方法成功
    {"$match": {"products._id": new mongoose.Types.ObjectId('58b77e509219010a6eac48ed')}}, 
    function(err, result){      if (err) {
        console.log(err);
      }else {
        res.send(result);
      }
    }
  );

mongoose中有两个地方定义了ObjectIdmongoose.schema.Types.ObjectIdmongoose.Types.ObjectId,在这里只有mongoose.Types.ObjectId才起作用。

关注我们

如果需要源码可以关注“IT实战联盟”公众号并留言(源码名称+邮箱),小萌看到后会联系作者发送到邮箱,也可以加入交流群和作者互撩哦~~~!



全部评论: 0

    我有话说:

    MongoDB实战:数据库备份恢复/导出导入

    mongodump命令可以通过参数指定导出的数据量级转存的服务器......

    MongoDB 查询文档(五)

    第一部分 前期准备1.1 插入测试数据db.test1.insertMany

    MongoDB系列---数据类型/插入文档(三)

    第一部分 BJSON JSON MongoDB的文档JavaScript中的对象很相似,JavaScript中的数据交互格式是JSON格式. JSON的数据格式: 1. null;2. 布尔

    MongoDB系列之----概述(一)

    MongoDB是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。

    MongoDB 数据库的基本操作(二)

    MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。

    MongoDB 更新/删除文档(四)

    第一部分 更新文档 文档存入数据库之后,就可以采用Update来修改它的内容, db.collection.update( #查询条件   <query>, #修改器

    Java Web实战-轻松提高千万级数据库查询效率

    通过优化数据库设计、java后台和数据库优化达到提高千万级数据查询的效率。

    MongoDB更新(五)

    如果数据库中尚未有数据, 准备测试数据db.test1.insertMany([    {"name": "zhangsan", "age": 19, "score": [90, 80]},    {"na...

    MongoDB 更新/删除文档(四)

    更新文档文档存入数据库之后,就可以采用Update来修改它的内容,db.collection.up

    MongoHelper 0.2.5 发布,Spring-Data-MongoDB 增强工具包

    工具包简化 CRUD 操作,并且提供了类 jpa 的数据库操作。

    专业解决 MySQL 查询速度慢性能差

    什么影响了数据库查询速度?关于数据库性能并不是DBA才关心的事。

    JAVA实现附近范围内公交定位问题

    接上【前端实战:通过JS抓取城市所有站点线路】获取附近定位信息

    前端实战:通过JS抓取城市所有站点线路

    做公交线路定位,木有数据怎么办?网上抓去~ 手把手教你通过JS实现站点线路数据抓取

    「性能架构」MySQL 8 查询优化新工具 Explain Analyze

    Explain 是我们常用的查询分析工具,可以对查询语句的执行方式进行评估,给出很多有用的线索。

    「免费」千万级电商高并发秒杀实战

    IT老齐 16年Java研发架构设计经验、前京东金融架构师、中国财政部数据平台架构师、专注送给小白的实战课、只为高薪而生、重实战,说人话,讲干货,不扯淡!

    移动H5前端五大性能优化方案(实战

    移动H5前端五大性能优化方案(实战

    抖音品质建设 - iOS启动优化《实战

    实战,本文是实战。 原理:抖音品质建设-iO...

    深度好文!RocketMQ高级进阶知识精讲

      https://juejin.cn/post/6944894142652612638 前言 大家好,我是jack xu,本文是RockeMQ精讲系列的最后一,讲的是RockeMQ一些