一、简述

MongoDB中使用find来进行查询。查询就是返回一个集合中文档的子集,子集合的范围从0个文档到整个集合。默认情况下,"_id"这个键总是被返回,即便是没有指定要返回这个键。("_id"是一个集合中每个文档的唯一标识)

查询的使用上有限制,传递给数据库的查询文档必须是常量。(当然,在你的代码里可以是正常的变量)

一个键可以有任意多个条件,但是一个键不能对应多个更新修改器。

条件语句是内层文档的键,而修改器是外层文档的键。

二、使用find或者findOne函数和查询文档对数据库执行查询

1、db.userInfo.find()
--查询所有数据,相当于 select * from userInfo

2、db.userInfo.find({age:22})
--查询 age = 22 的记录,相当于 select * from userInfo where age = 22

3、db.userInfo.find({age:22,name:'zhangsan'})
--查询 age = 22 并且name = 'zhangsan' 的记录,相当于  select * from userInfo where age = 22 and name = 'zhangsan'

tips:匹配正则表达式(4、5):

4、db.userInfo.find({name:/mongo/})
--查询 name 中包含 mongo 的数据, 相当于 select * from userInfo where name like '%mongo%'

5、db.userInfo.find({name:/^mongo/})
--查询 name 中以mongo开头的,相当于 select * from userInfo where name like 'mongo%'

6、db.userInfo.findOne()
--查询第一条数据,相当于 select top 1 * from userInfo 与 db.userInfo.find().limit(1)

7、db.userInfo.distinct("name")
--查询后去掉当前集合中的某列的重复数据,相当于 select distinct name from userInfo

tips:find 查询的第一个大括号表示查询条件,第二个大括号表示要显示的字段(默认全显示 ):

8、db.userInfo.find({},{name:1,age:1})
--查询指定列name、age的数据,相当于 select name,age from userInfo

9、db.userInfo.find({},{name:0})
--不希望结果集中显示 name 这个字段

tips:排序分页

10、db.userInfo.find().sort({age:1})
--按照年龄升序
11、db.userInfo.find().sort({age:-1})
--按照年龄降序

12、db.userInfo.find().limit(5)
--查询前5条数据,相当于 select top 5 * from userInfo

13、db.userInfo.find().skip(10)
--查询 10条以后的数据 select * from userInfo where id not in (select top 10 * from userInfo)

14、db.userInfo.find().limit(5).skip(0)
--可用于分页 limit是pageSize,skip是 第几页*pageSize(从第0页开始)

15、db.userInfo.find({sex:null}) 

-- 特定类型的查询,比如 null 。它确实可以匹配自身,但是它不仅可以匹配这个键为 null 的文档,也能匹配不包含这个键的文档。如果仅想匹配这个键位 null 的文档,需要修改如下:

-- db.userInfo.find({sex:{'$in':[null],'$exists':true}})

三、使用$条件查询实现范围查询、数据集包含查询、不等式查询,以及其他一些查询

1、$lt(小于)、$lte(小于等于)、$ge(大于)、$gte(大于等于)、$ne 不等于

db.userInfo.find({age:{$gt:22}})
    --查询age > 22 的记录,相当于 select * from userInfo where age > 22
db.userInfo.find({age:{$lt:22}})
    --查询age < 22 的记录,相当于 select * from userInfo where age < 22
db.userInfo.find({age:{$gte:22}})
   --查询 age >= 22 的记录,相当于 select * from userInfo where age >= 22
db.userInfo.find({age:{$lte:22}})
   --查询 age <= 22 的记录 ,相当于 select * from userInfo where age <= 22
db.userInfo.find({age:{$gte:23,$lte:26}})
   --查询 age >= 23 并且 age <=26 的记录 , 相当于 select * from userInfo where age >= 23 and age <=26

db.userInfo.find({age:{$ne:23}})
    --查询 age != 23 的记录 , 相当于 select * from userInfo where age != 23

tips:很遗憾,并没有 $eq(等于)这个操作符。

2、元条件句 $and 、$or、$not

         元条件句:即可以用在任何其他条件之上 。

$and 总是希望尽可能用最少的条件来限定结果的范围

db.userInfo.find({"$and" : [{x : {"$lt" : 1}}, {x : 4}]})
    --会匹配那些"x"字段的值小于1并且等于4的文档。虽然这两个条件看起来是矛盾的,但是这是完全有可能的,比如,如果"x"字段的值是这样一个数组{"x" : [0,4]},那么这个文档就与查询条件相匹配。
    --查询优化器不会对"$and"进行优化,这与其他操作符不同。如果把上面的查询改成下面这样,效率会更高:db.userInfo.find({x : {"$lt" : 1, "$in" : [4]}})

$or 第一个条件应该尽可能匹配更多的文档,这样才是最为高效的

db.userInfo.find({$or:[{age:22},{age:25}])
    --or与查询,相当于select * from userInfo where age = 22 or age = 25

$not 用在其他条件上的取反,虽然是元条件句,但是不能放在外层文档(否则:unknown top level operator: $not),并且后面必须跟正则表达式或者文档(否则:$not needs a regex or a document)。

db.userInfo.find({age:{'$not':{$gt:23}}});
    -- 对于 age>23 返回的文档取反集
db.product.find({name:{$not:/ang/}});
   -- 对 name 与正则匹配的结果取反集合

3、$in、$nin、$all、$size、$slice 、$elemMatch

$in 可以用来查询一个键的多个值
 db.userInfo.find({age : {"$in" : [22, 23, 24]}})
    --查询年龄等于22、23、24的文档
$nin$in 相反,用来查询一个键不属于多个值的文档。

$all (匹配数组)
db.food.find({fruit : {$all : ["apple", "banana"]}})
   -- 查询 fruit 既含有 apple,又含有banana 的文档。
   -- 当然,也可以不使用$all 匹配数组,比如 db.food.find({fruit : ["apple", "banana","orange"]}) 但是,这样子只能唯一匹配数组为["apple", "banana","orange"] 的文档,而且查询数组条件还要保证相同的元素顺序。
   --可以使用 key.index 查询数组特定位置的元素。db.food.find({"fruit.2" : "peach"})

$size(匹配数组)
    --db.food.find({"fruit" : {"$size" : 3}})
    --匹配数组长度为3的文档

$slice(匹配数组)
  --$slice 用在find的第二个参数,用来查找某个键匹配的数组元素的一个子集。
  --使用"$slice"时将返回文档中的所有键。
  --db.blog.findOne({},{comments:{"$slice":2}}) 返回 结果文档中comments数组的前两个子集
  --db.blog.findOne({},{comments:{"$slice":[23,10]}}) 返回 结果文档中comments数组的 24-33 子集,不够则全返回。
  --db.blog.findOne({},{comments:{"$slice":-1}}) 返回 结果文档中comments数组的最后一个子集

$elemMatch(匹配数组)
  --查询匹配有两种。数组匹配和非数组匹配。非数组匹配必须键的值满足每一条查询条件才行。数组匹配只要键的数组元素分别满足查询条件即可。比如:

-- $elemMatch 可以让数组的元素分别要满足查询条件,但是 $elemMatch 不会匹配非数组元素!!

-- db.test.find({"x" : {"$elemMatch" : {"$gt" : 10, "$lt" : 20}})

4、其他 $exists 、$mod

$exists
   --查询某个键时候存在
  -- db.userInfo.find({sex:{$exists:true}}) 返回键名含有sex的文档
  -- db.userInfo.find({sex:{$exists:false}}) 返回键名不含有sex的文档

$mod
  --$mod会将查询的值除以第一个给定值,若余数等于第二个给定值则匹配成功
  -- db.userInfo.find({id : {"$mod" : [5, 1]}}

四、查询将会返回一个数据库游标,游标只会在你需要时才将需要的文档批量返回

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

var cursor = db.driverLocation.find();
while (cursor.hasNext()){
var object = cursor.next();
print(object.type);
}

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

var cursor = db.driverLocation.find();
cursor.forEach(function(x){
print(x.type);
});    

调用find时,shell并不立即查询数据库,而是等待真正开始要求获得结果时才发送查询,这样在执行之前可以给查询附加额外的选项。几乎游标对象的每个方法都返回游标本身,这样就可以按任意顺序组成方法链。例如,下面几种表达是等价的:

> var cursor = db.foo.find().sort({"x" : 1}).limit(1).skip(10);
> var cursor = db.foo.find().limit(1).sort({"x" : 1}).skip(10);
> var cursor = db.foo.find().skip(10).limit(1).sort({"x" : 1});

此时,查询还没有真正执行,所有这些函数都只是构造查询。当执行 cursor.hasNext() 的时候,查询才真正被执行。这时,查询被发往服务器。shell立刻获取前100个结果或者前4 MB数据(两者之中较小者),这样下次调用next或者hasNext时就不必再次连接服务器取结果了。客户端用光了第一组结果,shell会再一次联系数据库,使用getMore请求提取更多的结果。getMore请求包含一个查询标识符,向数据库询问是否还有更多的结果,如果有,则返回下一批结果。这个过程会一直持续到游标耗尽或者结果全部返回。

游标的生命周期:首先,游标完成匹配结果的迭代时,它会清除自身。另外,如果客户端的游标已经不在作用域内了,驱动程序会向服务器发送一条特别的消息,让其销毁游标。最后,即便用户没有迭代完所有结果,并且游标也还在作用域中,如果一个游标在10分钟内没有使用的话,数据库游标也会自动销毁。

五、还有很多针对游标执行的元操作,包括忽略一定数量的结果,或者限定返回结果的数量,以及对结果排序。

MongoDB处理不同类型的数据是有一定顺序的。有时一个键的值可能是多种类型的,例如,整型和布尔型,或者字符串和 null。如果对这种混合类型的键排序,其排序顺序是预先定义好的。优先级从小到大,其顺序如下:

1. 最小值;
2. null;
3. 数字(整型、
4. 字符串;
5. 对象/文档;
6. 数组;
7. 二进制数据
8. 对象ID;
9. 布尔型;
10. 日期型;
11. 时间戳;
12. 正则表达式
13. 最大值 。

不用 skip 进行分页

如前文提到的,一般分页我们用 db.userInfo.find().limit(pageSize).skip(第n页 * pageSize) 来实现。但是我们注意到,如果数据量大的话,我们总是先取出前 n*pageSize 的条数然后再舍弃掉,显得很不合算。为此,《MongoDB权威指南》向我们介绍了一种方式:利用时间进行排序,拿到前一页的最后时间,取出时间大于上一页最后时间的 pageSize 条记录,如下:

var latest = null;
//显示第一页
var page1 = db.foo.find().sort({"date" : -1}).limit(100)
while (page1.hasNext()) {
latest = page1.next();
display(latest);
}
// 获取下一页
var page2 = db.foo.find({"date" : {"$gt" : latest.date}});
page2.sort({"date" : -1}).limit(100);

但是,我发现这样写还是会存在很多问题,比如说:

1、跟上一页最后一个文档的时间一样的文档如果有多个呢?那这样不是会导致一些文档被漏掉了吗?

2、上一页、下一页或许可以解决。那么如果用户点击第四页、第五页呢?

获取一致结果

数据处理通常的做法是先将数据从数据库中取出来,做一些变换以后,再保存回数据库。但是,MongoDB这边有个机制就是,如果拿出来处理的数据处理后导致体积比原先大很多,会导致数据放不回原来的位置,而把这个数据挪至集合的末尾处。从而引发的隐患就是:分页查询到最后一页的时候,又取到了原来的数据。

应对这个问题的方法就是对查询进行快照(snapshot)。如果使用了这个选项,查询就在"_id"索引上遍历执行,这样可以保证每个文档只被返回一次。

db.foo.find().snapshot()
    快照会使查询变慢,所以应该只在必要时使用快照。例如,mongodump默认在快照上使用查询。

MongoDB系列一(查询).的更多相关文章

  1. 3.MongoDB系列之查询

    1. find简介 // 查询所有文档 db.users.find({}) // 查询指定条件文档 db.users.find({'name': 'shenjian'}) // 查询指定字段,1查询键 ...

  2. MongoDB系列(二):C#应用

    前言 上一篇文章<MongoDB系列(一):简介及安装>已经介绍了MongoDB以及其在window环境下的安装,这篇文章主要讲讲如何用C#来与MongoDB进行通讯.再次强调一下,我使用 ...

  3. MongoDB 系列文章

    MongoDB 系列文章 本文的内容是基于 MongoDB 4.0 的. 参考于 MongoDB 4.0 官方文档. 搭建 MongoDB从搭建到优化 MongoDB-副本集搭建与管理 管理 Mong ...

  4. mongodb系列之-治理mongodb->db.currentOp()

    mongodb系列之-管理mongodb->db.currentOp() 管理mongodb->db.currentOp(), 绝对是原创... 今天公司的dba在内部分享了针对mysql ...

  5. Sql Server来龙去脉系列之三 查询过程跟踪

    我们在读写数据库文件时,当文件被读.写或者出现错误时,这些过程活动都会触发一些运行时事件.从一个用户角度来看,有些时候会关注这些事件,特别是我们调试.审核.服务维护.例如,当数据库错误出现.列数据被更 ...

  6. MongoDB 覆盖索引查询

    MongoDB 覆盖索引查询 官方的MongoDB的文档中说明,覆盖查询是以下的查询: 所有的查询字段是索引的一部分 所有的查询返回字段在同一个索引中 由于所有出现在查询中的字段是索引的一部分, Mo ...

  7. MongoDB 入门之查询(find)

    MongoDB 入门之查询(find) 1. find 简介 (1)find的第一个参数决定了要返回哪些文档. 空的查询文档会匹配集合的全部内容.默认就是{}.结果将批量返回集合c中的所有文档. db ...

  8. MongoDB系列之二(主动复制)

    目前我正在进行MongoDB的双机热备方面相关的工作.根据我目前看到的MongoDB方面的材料,MongoDB的实际部署有三种方式,分别是“主动复制”,“副本集”以及“分片副本集”. 首先我们从最简单 ...

  9. MongoDB系列三(Spring集成方案).

    一.前言 MongoDB是最为流行的开源文档数据库之一.Spring Data MongoDB提供了三种方式在Spring应用中使用MongoDB: 通过注解实现对象-文档映射: 使用MongoTem ...

  10. mongodb系列之---副本集配置与说明

    在配置副本集之前,我们先来了解一些关于副本集的知识. 1,副本集的原理 副本集的原理与主从很相似,唯一不同的是,在主节点出现故障的时候,主从配置的从服务器不会自动的变为主服务器,而是要通过手动修改配置 ...

随机推荐

  1. Redis基础及入门

    一. 什么是 Redis            Redis 是一个可基于内存,有着完备的持久化机制并以 Key-Value 形式存储的非关系型数据库.也称为数据结构服务器.    二. Redis 的 ...

  2. Spring-mvc 静态资源不拦截

    在Spring-mvc.xml文件中加入这个就可以了 <!-- 用于对静态文件进行解析 --> <mvc:annotation-driven /> <mvc:resour ...

  3. mysql存储引擎、事务

    MySQL存储引擎介绍 文件系统 操作系统组织和存取数据的一种机制. 文件系统是一种软件. 文件系统类型 ext2  ext3  ext4  xfs 数据 不管使用什么文件系统,数据内容不会变化 不同 ...

  4. Yii2 场景

    下面给大家介绍一下 yii2.0 场景的使用. 现在在 post表里面有 title image content 三个的字段,当我创建一个 post 的时候,我想三个字段全部是必填项,但是你修改的时候 ...

  5. iOS中的定时器

    据我所知,iOS中的定时器有两种.一个叫NSTimer,一个叫CADisplayLink.还有一种是使用GCD,不常用,这里就不介绍了. 下边说下两个定时器分别得用法: =============== ...

  6. MySQL取得某一范围随机数

    ①直接取值 若要在i ≤ R ≤ j 这个范围得到一个随机整数R ,需要用到表达式 FLOOR(i + RAND() * (j – i + 1)). 例如, 若要在7 到 12 的范围(包括7和12) ...

  7. Java三大特性(封装,继承,多态)

    Java中有三大特性,分别是封装继承多态,其理念十分抽象,并且是层层深入式的. 一.封装 概念:封装,即隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别:将抽象得到的数据 ...

  8. 【其他】Objective-C 内存管理学习总结

    转载请注明出处:http://www.cnblogs.com/shamoyuu/p/OC_CG.html 最近学习了Objective-C语言(以下简称OC),其他的都还好,唯有它的内存管理让我不知所 ...

  9. 用SDL库播放yuy2 Packed mode

    #define SDL_YUY2_OVERLAY 0x32595559 /* Packed mode: Y0+U0+Y1+V0 */ if (SDL_Init(SDL_INIT_VIDEO) < ...

  10. HighCharts之2D对数饼图

    HighCharts之2D对数饼图 1.实例源码 LogarithmicPie.html: <!DOCTYPE html> <html> <head> <me ...