查询
find介绍
第一个参数代表着查询的内容,默认是查询 {} 即所有文档。
> db.users.find()
当你添加键值对时,就意味着添加了查询条件。
> db.users.find({"age":27})
指定需要返回的键
第二个参数可以设置返回的键。
只显示 username
键和 email
键。
> db.users.find({}, {"username":1, "email":1})
不显示 _id
键
> db.users.find({}, {"username":1, "_id":0})
查询条件
$gte:大于等于
$lte:小于等于
$gt:大于
$lt:小于
$ne:等于
age
大于等于18小于等于30的所有文档
> db.users.find({}, {"age": {"$gte":18, "$lte", 30})
- $in:查询一个键的多个值
年龄为18和21的所有用户
> db.users.find({"age": {"$in": [18, 21]})
- $nin:没有在其中的
年龄不是为18和21的所有用户
> db.users.find({"age": {"$nin": [18, 21]})
- $or:满足多个条件之一的
年龄为18或者名字为tom的所有用户
> db.users.find({"age": {"$or": [{"age": 18}, {"username": "tom"}]})
- $mod:取模运算
将查询的值除以第一个给定值,若余数等于第二个给定值则匹配成功。
id为1、6、11、16等的用户
> db.users.find({"id_num": {"$mod": [5, 1]}})
- $not:不满足条件的
id为2、3、4、5、7、8、9、10、12等的用户
> db.users.find({"age": {"$or": [{"age": 18}, {"username": "tom"}]})
条件语义
条件语句内层文档的键,而修改器是外层文档的键。
可以对一个键应用多个条件:
> db.users.find({"age": {"$lt": 30, {"$gt": 20}]})
一个键可以有多个条件,但不能对应多个更新修改器。对于查询条件没有这样的限定。
有些原操作符也位于外层文档中,比如“$and”、“$or”和“$nor”。
> db.users.find({"and": [{"x": {"$lt" : 1}}, {"x" : 4}]})
{"x":[0,4]}
查询优化器不会对 $and
进行优化,改成下面的查询效率会更高:
> db.users.find({"x": {"$lt" : 1, "$in" : [4]}})
特定类型的查询
null
null 不仅会匹配某个值为 null 的文档,而且还会匹配不包含这个键的文档。所以这种匹配会返回所有的文档:
> db.c.find({"x" : null})
{"_id": ObjectId("4ba0f0dfd22aa494fd523621"), "y": null}
{"_id": ObjectId("4ba0f0dfd22aa494fd523621"), "y": 1}
如果只是想匹配键值为 null 的文档,既要检查改键的值是否为 null ,还要通过 $exists
条件判定键已经存在。
> db.c.find({"x" : {"$in": [null],"$exitists": true }})
正则表达式
符合 PCRE 的正则表达式都可以使用,在 mongodb 中正则表达式可以匹配自身。
查询数组
$all
通过多个元素匹配数组
> db.c.find({"fruit" : {"$all": ["apple", "banana"] }})
{"_id": 1, "fruit": ["apple", "banana", "peach"]}
{"_id": 3, "fruit": ["cherry", "banana", "apple"]}
$size
查询特定长度长度的数组
> db.c.find({"fruit" : {"$size": 3 }})
$slice
返回某个键匹配的数组元素的一个子集
返回前十个评论:
> db.blog.posts.findOne(criteria,{ "comments": {"$size": 10 }})
可以设置偏移量以及希望返回的元素数目
返回第 24~33个元素:
> db.blog.posts.findOne(criteria,{ "comments": {"$size": [23, 10] }})
使用 $slice 默认会返回所有键,不需要显示地声明在说明符中。
返回一个匹配的数组元素
可以使用 $ 获得一个匹配的元素
获取博客文章的第一篇:
> db.blog.posts.find({ "comments.name" : "bob"}, {"comments.$" : 1})
数组与查询范围的相互作用
> db.test.find({ "x" : {"$gt" : 10, "$lt": 20})
{"x" : 15}
{"x" : [5,25]}
你本希望得到的是 {“x” : 15} ,但是数组也被匹配到了。
有几种方式你可以得到预期的行为。首先,可以使用 $elemMatch
要求 MongoDB 同时使用查询条件中的两个语句中的两个语句与一个数组元素进行比较,它不会匹配非数组元素。
> db.test.find({ "x" : {"$elemMatch" :{"$gt" : 10, "$lt": 20}})
查询内嵌文档
查询内嵌文档与普通文档的方式是相同的。但是要查询一个完整的子文档,子文档必须准确匹配。通常只针对内嵌文档的特定键值查询,即时数据模式改变,也不会导致所有查询因为精确匹配失败。
使用模糊的命名条件句指定匹配数组的单个内嵌文档:
> db.blog.find({ "comments":{"$elemMatch":{"author":"joe","score":{"$get":5}}})
$where 查询
当键值对的查询方式无法满足需求,可以使用 $where 查询,它可以在查询中执行任意 JavaScript 。它会造成一些安全或者性能的问题,要尽量避免使用这种方式。
游标
limt、skip 和 sort
limt 指定的是上限
> db.blog.find().limt(3)
sort 指定升序(1)降序(-1)
> db.users.find().sort({"username" :1 , "age" : -1})
skip 指定偏移量
一页50,从第51个,降序:
> db.stock.find({"desc":"mp3"}).limit(50).skip(50).sort({"price" : -1})
排序时的比较顺序
最小值
null
数字(整型、长整型、双精度)
字符串
对象/文档
数组
二进制数据
对象 ID
布尔型
日期型
时间戳
正则表达式
最大值
避免使用 skip 略过大量结果
不要用 skip 对结果分页
不要用 skip 随机选取文档
高级查询选项
- $maxscan:integer
指定本次查询中扫描文档数量的上限。
> db.stock.find(criteria)._addSpecial("$maxscan", 20)
- $min:document
查询的开始条件(查询的下边界)。这样的查询,文档与索引必须完全匹配。
- $max:document
查询的结束条件(查询的下边界)。这样的查询,文档与索引必须完全匹配。
- $showDiskLoc:true
用于显示该条结果在磁盘的位置。
> db.stock.find(criteria)._addSpecial("$showDiskLoc", true)
{"_id": 0, "$diskLoc": {"file":2,"offset":154812592}}
获取结果一致性
由于更新时文档的原空间不足,内容变大的文档会重新分配位置。这导致查询时,会多次返回同一个文档。应对这个问题的方法就是对查询进行快照。这样就能让文档只返回一次,但是会使得查询变慢。
> db.stock.find().snapshot()
参考
[1] MongoDB权威指南