一、基本查询(find)
1、find、findOne
db.test.find(); # 默认查询条件为{},查询全部test集合的文档,可以根据条件进行过滤
db.test.findOne(); # 默认查询条件为{},查询满足条件的文档,返回第一条数据
2、指定字段查询
按照条件查询返回文档,并且第二个对象参数指定需要返回的字段,默认会返回所有的字段(即字段值为1),不返回需要指定字段值为0 ,既节省了mongo查询时候的数据量和传输量,也让客户端反序列化的时间和内存消耗。
1、_id默认会进行返回,除非特别指定为0,不进行返回。
2、其他字段不进程任何指定,默认全部返回。有指定返回的情况下,没有指定则不返回;反之,有指定不返回的情况下,其他则全部返回
db.test.find({}, {"name": 1,"_id":0});
二、条件查询
1、$lt、$lte、$gt、$gte(范围查找)
使用对象进行查询的时候,就是等于(=)符合,则需要查询范围时候则使用上面的符号,意思一目了然。
db.test.find({"_id":{"lte":5}}); # 查询主键id小于5的集合, 默认插入了10000条数据
2、$or、$in、$nin(后面一定是数组对象)
1)、默认查询的对象条件就是and关联符,所以尽量将能过滤掉最多的条件放前面;
db.user.find({"name":"kevin","age":NumberInt("5")}); # 查询名称为kevin并且(and)年龄为5的集合
2)、$or操作则需要后面跟的对象是一个对象的各个条件是or操作,并在尽量使用第一个条件就能查询满足条件比较多的文档
db.user.find({"$or":[{"_id":NumberInt("3")},{"name":"kevin5"}]}); # 主键为3或者名称为kevin5的文档
3)、$in和$nin(not in操作),则比较好理解,直接是in(或者not in)一个集合
db.user.find({"name":{"$in":["kevin7","kevin8","kevin10"]}}); # 名称在后面的数组中的集合
3、$not(取反操作,可对任何条件取反)
db.user.find({"name":{"$not":{"$nin":["kevin7","kevin8","kevin10"]}}}); # 名称不在数组中,再取反,与上面结果应该一致
4、$mod(取模判断条件是否满足)
db.user.find({"_id":{"$mod":[5000,2]}}); # 主键_id取模5000,余数为2的文档
5、$and、$nor(not or)、$or等,一个字段满足多个条件
db.user.find({"$and":[{"_id":{"$lte":70}},{"_id":50]}}); # 同一个字段的值,同时满足多个条件
6、null、$exists
mongo不像关系型数据库,可能会存在键的值为null或者其他文档存在某一个键,而其他文档不存在的情况。null会查询出所值为null和键不存在的文档,而$exist(boolean类型)则用于查询是否存在某个字段
db.test.find({"department":null}); # 查询部门为null及部门不存在的文档
db.test.find({"department":{"$exists":true}}); # 查询部门字段存在的值 null查询 = null + $exists
7、正则表达式(/需要匹配的字符?/i)
与一般使用的正则表达式一样,Mongo使用Perl兼容的正则表达式(PCRE),语法方式:
1)、 /需要匹配的字符/i 其中i可写可不写,可以匹配大小写忽略
2)、 需要匹配的字符可以使用 ^ 表示开头,?表示匹配任何
db.user.find({"name":/^KEVIN50?/i}); # 匹配字符kevin50开头,忽略大小写的所有文档
8、数组查询
1)、$all
db.test.find({"movieId":{"$all":[1,3]}}); # 用户同时喜欢电影id为1和3的文档
2)、$size
db.test.find({"movieId":{"$size":2}}); # 用户喜欢的电影只有两个的文档
3)、$slice
find的第二个参数是可选项,用于设置指定需要返回的字段(见最上面一、基本查询的第二条)。不仅可以用于指定返回那些字段,还可用于执行返回的字段的前几条或后几条($slice,整数表示前多少条,负数反之)。
db.test.find({},{"movieId":{"$slice": -1}}); # 返回文档条件的文档,但是需要过滤喜欢的电影,都只返回最好一个
db.test.find({},{"movieId":{"$slice":[1,2]}}); # 查询范围偏移量
4)、指定数组元素的第几个($)
与slice比较相同,但是slice用于指定返回的前后的范围,但是不能精确的返回元素的第一个,可以用一个$符合进行查询,下标从1开始:
db.test.find({},{"movieId.$": 2}); # 满足条件的文档,值返回第二个数组的元素(即喜欢的第二个电影)
9、内嵌文档
内嵌文档可以使用正常的对象方式进行查询,也可以使用 (父字段名称.子字段名)方式进行查询:
db.test.find({"name":{"first":"kevin","last":"li"}}); # 查询第一个名称为kevin,第二个名称为li的文档,等价于下面的:
db.test.find({"name.first":"kevin","name.last":"li"}); # 同上
10、$where子语句
$where子语句能够满足比较复杂的子查询,但是需要在服务端使用脚本进行设置,为安全起见,一般建议禁止使用。
三、MongoDB分页
1、$limit、$skip、$sort(排序分页)
db.user.find({}).skip(100).limit(10).sort({"name":1}); # 按照名称正序,跳过100条,查询10条数据
2、分页数非常大的时候的优化
MongoDB与mysql一样,当分页查询需要过滤到很多的文档时性能特别低(每次需要查询非常多的文档,然后进行skip),所以像mysql一样,会有以下两种做法:
1)、查询的时候,若对数据要求性不是那么高,比如展示给用户看的信息。则可以使用id>越过数,在limit的方式
2)、若类似我们现在,每天搜索系统需要同步一次好几张表的全量数据,则可以在查询的时候,要求上一次返回查询的最后一条数据的id或者时间,先进行大于(_id或者时间)等操作,并且该操作一般会使用索引,然后再进行limit操作。
而对于mongoDB还有一个非常重要的特性就是游标(Cursor),并且我们的项目中也已经在使用(但是游标使用也需要注意很多问题),后面进行专门讲解。