查询内嵌文档

数据准备

> db.blog.find().pretty()
{
"_id" : ObjectId("585694e4c5b0525a48a441b5"),
"content" : "...",
"comments" : [
{
"comment" : "good post",
"author" : "jim",
"votes" :
},
{
"comment" : "i thought it was too short",
"author" : "yyb",
"votes" :
},
{
"comment" : "free watches",
"author" : "alice",
"votes" :
}
]
}
{
"_id" : ObjectId("585f659898992d5a44085fc0"),
"content" : "query",
"comments" : [
{
"comment" : "good post two",
"author" : "yyb",
"votes" :
},
{
"comment" : "i thought it was vary good",
"author" : "mmq",
"votes" :
},
{
"comment" : "free watches two",
"author" : "lf",
"votes" :
}
]
}
>

方式1:查询整个内嵌文档

与普通查询完全相同。但是,如果要查询一个完整的子文档,那么子文档必须精确匹配(顺序以及个数都要一样)。

> db.blog.find({"comments":{"author":"lf","votes":20}})
 >

> db.blog.find({"comments":{"comment":"free watches two","author":"lf","votes":}}).pretty()
{
"_id" : ObjectId("585f659898992d5a44085fc0"),
"content" : "query",
"comments" : [
{
"comment" : "good post two",
"author" : "yyb",
"votes" :
},
{
"comment" : "i thought it was vary good",
"author" : "mmq",
"votes" :
},
{
"comment" : "free watches two",
"author" : "lf",
"votes" :
}
]
}
>

方式2:只针对其键/值对进行查询

> db.blog.find({"comments.author":"yyb","comments.votes":}).pretty()
{
"_id" : ObjectId("585f659898992d5a44085fc0"),
"content" : "query",
"comments" : [
{
"comment" : "good post two",
"author" : "yyb",
"votes" :
},
{
"comment" : "i thought it was vary good",
"author" : "mmq",
"votes" :
},
{
"comment" : "free watches two",
"author" : "lf",
"votes" :
}
]
}

如果想要查找由yyb发表的11分以上的投票。不能直接使用以下方式

> db.blog.find({"comments":{"author":"yyb","votes":{"$gt":}}})
>

或者

> db.blog.find({"comments.author":"yyb","comments.votes":{"$gt":}})//本来没有,但却查出来两条
{ "_id" : ObjectId("585694e4c5b0525a48a441b5"), "content" : "...", "comments" : [ { "comment" : "good post", "author" : "jim", "votes" : }, { "comment" : "i thought it was too short", "author" : "yyb", "votes" : }, { "comment" : "free watches", "author" : "alice", "votes" : } ] }
{ "_id" : ObjectId("585f659898992d5a44085fc0"), "content" : "query", "comments" : [ { "comment" : "good post two", "author" : "yyb", "votes" : }, { "comment" : "i thought it was vary good", "author" : "mmq", "votes" : }, { "comment" : "free watches two", "author" : "lf", "votes" : } ] }

$elemMatch

要正确地指定一组条件,而不必指定每个键,就需要使用 $elemMatch 。这种模糊的命名条件句能用来在查询条件中部分指定匹配数组中的单个内嵌文档。

$elemMatch将限定条件进行分组,仅当需要对一个内嵌文档的多个键操作时才会用到。

> db.blog.find({"comments":{"$elemMatch":{"author":"yyb","votes":{"$gt":11}}}})//无匹配结果
> db.blog.find({"comments":{"$elemMatch":{"author":"yyb","votes":{"$gte":}}}}).pretty()
{
"_id" : ObjectId("585f659898992d5a44085fc0"),
"content" : "query",
"comments" : [
{
"comment" : "good post two",
"author" : "yyb",
"votes" :
},
{
"comment" : "i thought it was vary good",
"author" : "mmq",
"votes" :
},
{
"comment" : "free watches two",
"author" : "lf",
"votes" :
}
]
}
>

$where

用它可以在查询中执行任意的js。这样就能在查询中做任何事情,为安全起见,应该严格限制或消除$where语句的使用。应该禁止终端用户使用任意的$where语句。

如果函数返回true,文档就作为结果集的一部分返回;如果为false,就不返回。

使用$where在速度上要比常规查询慢很多。每个文档都要从BSON转换成js对象,然后通过$where表达式来运行。而且不能使用索引。实在不得已,最好先使用常规查询(或索引)进行过滤,然后使用$where语句,这样组合使用可以降低性能损失。

$where语句最常见的应用就是比较文档中的两个键的值是否相等。比如:

> db.foo.insert({"apple":,"banana":,"pach":})
WriteResult({ "nInserted" : })
> db.foo.insert({"apple":,"banana":,"pach":})
WriteResult({ "nInserted" : })
> db.foo.find({"$where":function(){
... for(var cur in this){
... for(var other in this){
... if(cur!=other && this[cur]==this[other]){
... return true;
... }
... }
... }
... return false;
... }});
{ "_id" : ObjectId("585f768398992d5a44085fc2"), "apple" : , "banana" : , "pach" : }
>

游标

数据库使用游标返回find的执行结果。客户端对游标的实现通常能够对最终结果进行有效地控制。可以限制结果的数量,略过部分结果,根据任意键按任意顺序的组合对结果进行各种排序,或者执行其他一些强大的操作。

> for(i=;i<;i++){
... db.coll.insert({x:i});
... }
WriteResult({ "nInserted" : })
> var cursor=db.coll.find()
> while(cursor.hasNext()){
... obj=cursor.next();
... print(obj.x+"============"+obj._id);
... }

0============585f7c3a98992d5a44085fc3
1============585f7c3a98992d5a44085fc4
2============585f7c3a98992d5a44085fc5
3============585f7c3a98992d5a44085fc6

......

 

cursor.hasNext()检查是否有后续结果存在,然后用cursor.next()获取它。

游标类还实现了js的迭代接口,所以可以在forEach循环中使用:

> var coll=db.coll.find({"x":{"$lte":}})
> coll.forEach(function(row){
... print(row._id+"========="+row.x);
... })
585f7d0298992d5a44086027=========
585f7d0298992d5a44086028=========
585f7d0298992d5a44086029=========
585f7d0298992d5a4408602a=========
>

调用find时,shell并不立即查询数据库,而是等待真正开始获得结果时才发送查询,这样在执行之前可以给查询附加额外的选项。

几乎游标对象的每个方法都返回游标本身,这样就可以按照任意顺序组成方法链。例如,下面几种表达是等价的:

> var cursor=db.coll.find().sort({"x":-}).skip(10).limit()//实现分页的方式:先倒序,跳过10条,取1条
> var cursor=db.coll.find().limit().sort({"x":-}).skip()
> var cursor= db.coll.find().skip().limit().sort({"x":-})

此时,查询还没有真正执行,所有这些函数都只是构造查询。

> print(cursor)

DBQuery: test.coll -> { "query" : { }, "orderby" : { "x" : - } }

limit、sort、和skip

limit限制返回结果的数量,sort排序,skip忽略一定数量的结果。

> var cursor=db.coll.find().sort({"x":-}).skip().limit()//实现分页的方式:先倒序,跳过10条,取1条
> db.coll.find().limit()
{ "_id" : ObjectId("585f7d0298992d5a44086027"), "x" : }
{ "_id" : ObjectId("585f7d0298992d5a44086028"), "x" : }
......
> db.coll.find().skip()
{ "_id" : ObjectId("585f7d0298992d5a44086029"), "x" : }
{ "_id" : ObjectId("585f7d0298992d5a4408602a"), "x" : }
......
> db.coll.find().sort({"x":-})
{ "_id" : ObjectId("585f7d0298992d5a4408608a"), "x" : }
{ "_id" : ObjectId("585f7d0298992d5a44086089"), "x" : }
......

避免使用skip略过大量结果,用skip略过少量的文档还是不错的。但是要是数量非常多的话,skip就会变得很慢,通常可以利用上次的结果来计算下一次查询条件。

比如可以利用最后一个文档中的“date”的值最为查询条件,来获取下一页:

> var page1=db.coll.find().sort({"date":-}).limit()
> var lastest=null;
> while(page1.hasNext()){ latest=page1.next(); print(latest.x)}
> var page2=db.coll.find({"date":{"$gt":latest.date}}).sort({"date":-}).limit()

比较顺序

MongoDB处理不同类型的数据是有一定顺序的。有时一个键的值可能是多种类型的。如果对这种混合类型的键排序,其顺序是预先定义好的。优先级从小到大,其顺序如下。

(1)最小值

(2)Null

(3)数字

(4)字符串

(5)对象/文档

(6)数组

(7)二进制数据

(8)对象id

(9)布尔型

(10)日期型

(11)时间戳

(12)正则表达式

(13)最大值

高级查询选项

简单查询

> var cursor=db.coll.find({"x":})

封装查询

有一些选项可以用于对查询进行“封装”。

比如:

var cursor= db.coll.find({x:{“$lt”:}}).sort({"x":-})

实际情况不是将 {x:{“$lt”:} 作为查询直接发送给数据库,而是先将查询封装在一个更大的文档中。

DBQuery: test.coll -> { "query" : { "x" : { "$lt" :  } }, "orderby" : { "x" : - } }

绝大多数驱动程序都提供了辅助函数,用于向查询中添加各种选项。比如:

> db.coll.find({"x":{"$lt":}})._addSpecial("$showDiskLoc",true);

{ "_id" : ObjectId("585f7d0298992d5a44086027"), "x" : , "date" : ISODate("2016-12-25T10:02:02.499Z"), "$recordId" : NumberLong() }

{ "_id" : ObjectId("585f7d0298992d5a44086028"), "x" : , "date" : ISODate("2016-12-25T10:02:02.499Z"), "$recordId" : NumberLong() }

> 

获取一致结果

数据处理通常做法就是先把数据从MongoDB中取出来,然后做一些变换,最后在存回去。

结果比较少时,没什么问题。但是如果结果集比较大,MongoDB可能会多次返回同一个文档。原因是:体积变大的文档,可能无法保存回原先的位置。MongoDB会为更新后无法放回原位置的文档重新分配存储空间。

解决方案:对查询进行快照。这样查询就在_id索引上遍历执行,这样可以保证每个文档只被返回一次。

> db.coll.find().snapshot()

快照会使查询变慢,如非必要,不建议使用。

游标生命周期

看待游标的两种角度:客户端游标以及客户端游标表示的数据库游标。前面所说的游标都是客户端游标。

在服务器端,游标消耗内存和其他资源。游标遍历尽了结果之后,获取客户端发来消息要求终止,数据库就会释放这些资源。还有一些情况导致游标终止:

  1. 游标完成匹配结果的迭代时。
  2. 客户端的游标已经不再作用域内,驱动程序会向服务端发送一条特别的消息,让其销毁游标。
  3. 一个游标在10分钟之内没有使用。

数据库命令

在shell中使用的辅助函数,都是对数据库命令的封装,而提供的更加简单的接口。

> db.runCommand({"drop":"coll"})
{ "ns" : "test.coll", "nIndexesWas" : , "ok" : }
> db.coll.drop()
false

查看所有的数据库命令

> db.listCommands()

数据库命令总会返回一个包含ok键的文档,如果值是1,则表示成功,反之失败,那么命令的返回文档中就会有一个额外的键errmsg。用于描述失败的原因。

>  db.runCommand({"drop":"coll"})
{ "ok" : , "errmsg" : "ns not found", "code" : }

MongoDB中的命令被实现为一种特殊类型的查询,这些特殊的查询会在$cmd集合上执行。

runCommand只是接受一个命令文档,并且执行与这个命令文档等价的查询。于是,drop命令会被转换为如下代码:

> db.$cmd.findOne({"drop":"coll"})
{ "ok" : , "errmsg" : "ns not found", "code" : }

有些命令需要管理员权限,而且要在admin数据库上才能执行。如果当前位于其他的数据库,但是需要执行一个管理员命令,可以使用 adminCommand

> db.runCommand({"shutdown":})
{
"ok" : ,
"errmsg" : "shutdown may only be run against the admin database.",
"code" :
}
> db.adminCommand({"shutdown":})
--25T21::31.474+ E QUERY [thread1] Error: error doing query: failed: network error while attempting to run command 'shutdown' on host '127.0.0.1:27017' :
DB.prototype.runCommand@src/mongo/shell/db.js::
DB.prototype.adminCommand@src/mongo/shell/db.js::
@(shell)::

MongoDB学习笔记六—查询下的更多相关文章

  1. MongoDB学习笔记六:进阶指南

    [数据库命令]『命令的工作原理』MongoDB中的命令其实是作为一种特殊类型的查询来实现的,这些查询针对$cmd集合来执行.runCommand仅仅是接受命令文档,执行等价查询,因此,> db. ...

  2. MongoDB学习笔记五—查询上

    数据准备 { , "goods_name" : "KD876", "createTime" : ISODate("2016-12- ...

  3. MongoDB学习笔记(六) MongoDB索引用法和效率分析

    MongoDB中的索引其实类似于关系型数据库,都是为了提高查询和排序的效率的,并且实现原理也基本一致.由于集合中的键(字段)可以是普通数据类型,也可以是子文档.MongoDB可以在各种类型的键上创建索 ...

  4. mongodb 学习笔记 3 --- 查询

    在mongodb的查询中可以通过使用如下操作符进行深度查询 1.条件操作符 $gt  $gte : >  >=   {"age":{"$gt":18 ...

  5. MongoDB 学习笔记之 查询表达式

    查询表达式: db.stu.find().count() db.stu.find({name: 'Sky'}) db.stu.find({age: {$ne: 20}},{name: 1, age: ...

  6. MongoDB学习笔记(转)

    MongoDB学习笔记(一) MongoDB介绍及安装MongoDB学习笔记(二) 通过samus驱动实现基本数据操作MongoDB学习笔记(三) 在MVC模式下通过Jqgrid表格操作MongoDB ...

  7. 【转】MongoDB学习笔记(查询)

    原文地址 MongoDB学习笔记(查询) 基本查询: 构造查询数据. > db.test.findOne() { "_id" : ObjectId("4fd58ec ...

  8. MongoDB学习笔记(六)--复制集+sharding分片 && 总结

    复制集+sharding分片                                                               背景 主机 IP 服务及端口 Server A ...

  9. MongoDB学习笔记:快速入门

    MongoDB学习笔记:快速入门   一.MongoDB 简介 MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统.在高负载的情况下,添加更多的节点,可以保证服务器性能.M ...

随机推荐

  1. 为你的Web程序加个启动画面

    .Net开发者一定熟悉下面这个画面: 这就是宇宙第一IDE Visual Studio的启动画面,学名叫Splash Screen(或者Splash Window).同样,Javar们一定对Eclip ...

  2. CSS float 浮动属性

    本篇主要介绍float属性:定义元素朝哪个方向浮动. 目录: 1. 页面布局方式:介绍文档流.浮动层以及float属性. 2. float:left :介绍float为 left 时的布局方式. 3. ...

  3. 关于VS2015 ASP.NET MVC添加控制器的时候报错

    调试环境:VS2015 数据库Mysql  WIN10 在调试过程中出现类似下两图的同学们,注意啦. 其实也是在学习的过程中遇到这个问题的,找了很多资料都没有正面的解决添加控制器的时候报错的问题,还是 ...

  4. 操作系统篇-hello world(免系统运行程序)

     || 版权声明:本文为博主原创文章,未经博主允许不得转载. 一.前言     今天起开始分享关于操作系统的相关知识,本人也是菜鸟一个,正处于学习阶段,这整个操作系统篇也是我边学习边总结的一些结果,希 ...

  5. MAVEN学习-第一个Maven项目的构建

    MAVEN安装成功之后就可以进行项目的构建和管理了: 为什么要用maven进行项目的构建和管理? 对于初学者来说一个最直接的也是最容易里的优点在于JAR包的管理,相对于以前开发一个项目的时候我们需要用 ...

  6. 基于NPOI的Excel数据导入

    从Excel导入数据最令人头疼的是数据格式的兼容性,特别是日期类型的兼容性.为了能够无脑导入日期,折腾了一天的NPOI.在经过测试确实可以导入任意格式的合法日期后,写下这篇小文,与大家共享.完整代码请 ...

  7. swift 中关于open ,public ,fileprivate,private ,internal,修饰的说明

    关于 swift 中的open ,public ,fileprivate,private, internal的区别 以下按照修饰关键字的访问约束范围 从约束的限定范围大到小的排序进行说明 open,p ...

  8. 跟着老男孩教育学Python开发【第二篇】:Python基本数据类型

    运算符 设定:a=10,b=20 . 算数运算 2.比较运算 3.赋值运算 4.逻辑运算 5.成员运算 基本数据类型 1.数字 int(整型) 在32位机器上,整数的位数为32位,取值范围为-2**3 ...

  9. Mono产品生命周期

    软件生命周期 同任何事物一样,一个软件产品或软件系统也要经历孕育.诞生.成长.成熟.衰亡等阶段,一般称为软件生命周期(软件生存周期) .软件生命周期模型是指人们为开发更好的软件而归纳总结的软件生命周期 ...

  10. 【腾讯Bugly干货分享】基于 Webpack & Vue & Vue-Router 的 SPA 初体验

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57d13a57132ff21c38110186 导语 最近这几年的前端圈子,由于 ...