MongoDB系列一(查询).
一、简述
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系列一(查询).的更多相关文章
- 3.MongoDB系列之查询
1. find简介 // 查询所有文档 db.users.find({}) // 查询指定条件文档 db.users.find({'name': 'shenjian'}) // 查询指定字段,1查询键 ...
- MongoDB系列(二):C#应用
前言 上一篇文章<MongoDB系列(一):简介及安装>已经介绍了MongoDB以及其在window环境下的安装,这篇文章主要讲讲如何用C#来与MongoDB进行通讯.再次强调一下,我使用 ...
- MongoDB 系列文章
MongoDB 系列文章 本文的内容是基于 MongoDB 4.0 的. 参考于 MongoDB 4.0 官方文档. 搭建 MongoDB从搭建到优化 MongoDB-副本集搭建与管理 管理 Mong ...
- mongodb系列之-治理mongodb->db.currentOp()
mongodb系列之-管理mongodb->db.currentOp() 管理mongodb->db.currentOp(), 绝对是原创... 今天公司的dba在内部分享了针对mysql ...
- Sql Server来龙去脉系列之三 查询过程跟踪
我们在读写数据库文件时,当文件被读.写或者出现错误时,这些过程活动都会触发一些运行时事件.从一个用户角度来看,有些时候会关注这些事件,特别是我们调试.审核.服务维护.例如,当数据库错误出现.列数据被更 ...
- MongoDB 覆盖索引查询
MongoDB 覆盖索引查询 官方的MongoDB的文档中说明,覆盖查询是以下的查询: 所有的查询字段是索引的一部分 所有的查询返回字段在同一个索引中 由于所有出现在查询中的字段是索引的一部分, Mo ...
- MongoDB 入门之查询(find)
MongoDB 入门之查询(find) 1. find 简介 (1)find的第一个参数决定了要返回哪些文档. 空的查询文档会匹配集合的全部内容.默认就是{}.结果将批量返回集合c中的所有文档. db ...
- MongoDB系列之二(主动复制)
目前我正在进行MongoDB的双机热备方面相关的工作.根据我目前看到的MongoDB方面的材料,MongoDB的实际部署有三种方式,分别是“主动复制”,“副本集”以及“分片副本集”. 首先我们从最简单 ...
- MongoDB系列三(Spring集成方案).
一.前言 MongoDB是最为流行的开源文档数据库之一.Spring Data MongoDB提供了三种方式在Spring应用中使用MongoDB: 通过注解实现对象-文档映射: 使用MongoTem ...
- mongodb系列之---副本集配置与说明
在配置副本集之前,我们先来了解一些关于副本集的知识. 1,副本集的原理 副本集的原理与主从很相似,唯一不同的是,在主节点出现故障的时候,主从配置的从服务器不会自动的变为主服务器,而是要通过手动修改配置 ...
随机推荐
- Java--JDBC连接与Django--DATABASES设置
JDBC 简介 JDBC(Java Data Base Connectivity,java 数据库连接)是一种用于执行 SQL 语句的 JavaAPI,可以为多种关系 数据库提供统一访问,它由一组用 ...
- 如何遍历 Windows 摄像头设备?
#include <stdlib.h> #include <iostream> #include <Windows.h> #include <comdef.h ...
- PAT乙级 1034
思路:是个水题,但是有坑.不能被题目忽悠了,题目保证正确的输出中没有超过整型范围的整数. 它只是保证结果不超出int,但是我们在运算过程中的乘法可能会超出int,直接把所有int改成long long ...
- uva 116 单向TSP
这题的状态很明显. 转移方程就是 d(i,j)=min(d(i+1,j+1),d(i,j+1),d(i-1,j+1)) //注意边界 我用了一个next数组方便打印结果,但是一直编译错误,原来是不能用 ...
- hdu1698 Just a Hook 线段树
共有Q个更新,每次更新给更新的区间一个标记,表示该区间是在哪一次被更新,最后统计答案是以最近被更新的值为答案. AC代码: #include<cstdio> const int maxn= ...
- mybatis与spring的整合(使用接口实现crud)
本人刚刚接触mybatis,今天把它和spring整合起来用了一个上午==. 一开始是通过配置文件来配置,后来尝试用了一下注解,觉得mybatis的注解真的有点恶心...一大坨的,所以我还是建议使用配 ...
- SecureCRT8.0设置语法高亮
SecureCRT默认不显示语法高亮,整个界面颜色单一,用起来很不舒服,也没有效率,所有通过设置一下语法高亮还是很有必要的, 默认字体也看着不是很清晰.所以还是修改一下预告高亮比较好 设置语法高亮,多 ...
- Unable to find the ncurses libraries的解决办法
我们在更新CentOS或者Ubuntu的内核时,执行make menuconfig可能看如这样的错误: *** Unable to find the ncurses libraries or the* ...
- 使用wordpress搭建独立域名的个人博客或网站
最近抽空闲时间搭建了一个独立域名的个人博客站点,基本过程如下: 一.准备工作: 1.准备一个独立的域名,我是从万网中注册的cn结束的域名:tuzongxun.cn,价格29元,根据个人选择,也有更高更 ...
- svnserve.conf: Option expected的问题解决方法
经常有新手配置基于svnserve的subversion服务器后,在客户端访问subversion版本库时出现这个错误:svnserve.conf:12: Option expected为什么会出现这 ...