简介
MongoDB中的查询使用db.collection.find/findOne()函数来完成。find函数返回包含0-n个文档的查询目标集合的子集合。
使用方法:
db.collection.find(query,fields,limit,skip,batchSize,options)
db.collection.findOne(query,fields,options)
参数说明:
query:
查询参数文档,文档中的多个key-value是以and的形式组合的,也就是查询条件是query中的key1=value1 and key2=value2 …。当query不存在或者为"{}"的时候默认返回整个查询目标集合。query文档对象中的value在传递给mongoDB的时候必须是常量。mongoDB不能解析/计算传递给它的查询文档中的value的变量。query文档中的key-value是按声明顺序执行的,所以可以根据不同的情况优化key-value的顺序。同时,queryDocObj中是可以将正则表达式(符合Perl标准)作为key的value来匹配条件。
比较条件句:
查询参数文档,不仅可以通过":"来作为等于的效果。也可以通过使用比较操作符来实现范围查找。mongoDB中的条件句比较操作符有:
$lt,lessthan,小于;$lte,lessthanequals,小于等于;$gt,greatthan,大于;$gte,greatthanequals,大于等于;$ne,notequals,不等于。
使用方式:{key:{比较运算符:value}}
OR条件句:
默认情况下,query文档中的key-value都是AND关系的。如果需要OR查询怎么处理呢。mongoDB提供了'$or'和'$in'条件句来进行or的查询,同一key的不同value的or关系使用'$in',$in后边的value必须是数组,即使只有一个元素:
find({key:{'$in':[value1,value2,value3…]}})
$nin==notin,与$in是相反关系,使用方式与'$in'相同。
如果是多个不同的key的or关系使用'$or':
find({'$or':[{key1:value1},{key2:value2}]})
NOT条件句:
$not是元条件句,可以用于任何的query文档对象之前,表示相反。例如:
find({'$not',{queryDocObj}})
query对象中的null
在mongoDB中,null是一种特殊的数据类型,所以它完全可以匹配集合中key值为null的文档。但是不仅仅如此,null也会匹配到没有该key值的文档对象。所以在使用null查询的时候一定要确定是要查询key的值为null的文档还是要查询key值不存在的文档。
如果查询key值为null且无key值的文档,那么直接使用{key:null}即可。
如果只查询key值为null,不要key值不存在的文档,那么需要使用$exist条件句,保证key存在:{key:{"$in":[null],'$exist':true}}
数组查询
数组值查询
当需要查询文档中的某个value为数组类型数据的时候,如果以一个元素值为限定条件可以直接使用:
find({key:数组某元素值})
如果以多个元素为限定,即目标数组中必须包含多个元素,就需要使用到$all条件句,$all条件句中的元素顺序不重要:
find({key:{'$all':[限定元素1,限定元素2….]}})
如果要查询指定位置的元素的值,可是使用下标(从0开始)的方式:
find({key.下标值:值})
数组长度查询
mongoDB为我们不仅为我们提供了基于数组中元素值的查询,也为我们提供了数组长度的查询。通过使用$size条件句,可实现数组长度为筛选条件的查询:
find{key:{'$size':目标长度}}
如果要查询长度范围,我们可能希望结合前边提到的$gt等比较条件句:
find{key:{'$size':{'$gt':3}}}
可惜在mongoDB并不支持这么使用,这么查询不会有结果。变通的条件是我们为文档对象添加一个key为size,value为数组长度的键值对。不过这么做我们必须保证每次对数组元素增减的时候同步更新size的值。例如
update({'$push':{key:'aaa'},'$inc':{'size':1}})或update({'$pop':{key:1},'$inc':{'size':-1}})
数组元素的返回值个数
当我们查询数组的时候,可能会限定数组元素的返回值个数,那么我们就需要用到$slice条件句,该条件句主要是为了限定返回的数组中元素的个数或元素的范围,默认情况下返回数组所在文档中的所有key。尤其要注意的是,该条件句是在find函数的第二个参数位置处使用。例如:
返回从前数n个元素:
find(queryDocObj,{数组key:{'$slice':n}}
返回从后数n个元素:
find(queryDocObj,{数组key:{'$slice':-n}})
通过偏移量来限定返回的元素范围:
find{queryDocObj,{数组key:{'$slice':[偏移量,个数]}}}
内嵌文档查询
对于内嵌文档查询,根据过滤条件分为两种情况:
根据某个条件过滤:
根据某单个条件过滤,比较简单,使用key.子文档key就可以,所以说文档中的key命名不能有".":find({key.subKey:value})即可以查询。
根据某几个条件过滤
当根据多个条件过滤时,我们必须保证多个过滤条件存在于一个内嵌文档中,那么就需要mongoDB中的$elemMatch条件句为我们保证我们提供的条件存在于一个内嵌文档中。
find({内嵌文档key:{'$elemMatch':{内嵌文档中的key1:value1,内嵌文档中key2:value2…}}})
复杂查询
上边提到的查询都是通过从外部给定某些条件来进行数据查询,如果以上介绍的方式无法查询的时候,就需要用到mongoDB为我们提供的$where条件句了。$where条件句最强大的功能是可以将JS函数作为过滤条件进行查询,这种方式几乎可以做到任何查询。但是要知道的,使用$where查询的速度较慢,而且不能使用索引,这要是因为使用$where时,BSON格式的数据转化为JS对象,然后才通过$where来运行,尽量不使用$where或将$where在常规查询之后。
$where例子:
find({'$where':function(){
for(var current in this){
for(var other in this){
if(current!=other&&this[current]==this[other]){
return true;
}
}
}
return false;
}})
上边的例子中this代表了集合中某个文档,current和other都是代表了文档中key/value,在JS中this[current]==this.current所以上边这个查询就是要查询key不同而value相同的那部分文档。
fields:
指定返回键参数,可以指定或者剔除某些key,但是_id这个key是无法指定或提出的。指定:{keyName:1}。剔除:{keyName:0}。当keyName的value值为1,那么就是指定该key作为结果文档中的一部分,如果value为0就是指结果文档中不包括该keyName。当fields不存在或使用'{}'时,表示返回默认key,即全部的key。
limit:
类似于mysql中的limit相似,都是要指明显示多少条记录,不要的时候使用{}来代表。不过这里只能是一个数字,配合下一个skip参数使用达到Mysql中的limit skip,num的效果。例如:
find({},{},3)
就是查询集合中所有文档中的前3个,返回所有key-value。
skip:
与mysql中的offset相同,指明了返回的集合中第一个文档的偏移量。当偏移量过多的时候会降低性能,可以通过添加查询项(大于某个值)等方式减少偏移量。例如:
find({},{},{},4)
就是查询集合中从第5个开始(偏移4个文档)的所有文档,返回所有key-value。
游标:
MongoDB中的游标概念与传统的关系型数据库中游标的概念相似,都是指代查询的结果集一个缓存空间,同时使用游标位置来定位当前游标指向的某条记录/文档。
在MongoDB中,find的返回值赋给的游标对象支持hasNext()来判断是否有下一个文档,或forEach(function(doc){})的迭代器方式遍历。
服务器端的游标会占用服务器内存等资源,所以当游标使用完会自动销毁。或者当创建的游标10分钟不使用,服务器端也会自动的将该游标销毁。
查询结果排序
mongoDB提供了sort方法对结果集(游标)排序,排序参数是一个文档,可以按多个key排序。value值为1则为升序,-1为降序:
find().sort({key1:1,key2:-1})
mongoDB高级查询
所谓的高级查询,实际上就是对查询的结果进行更详细的设置。所以说高级==详细(个人拙见)。例如上边的提到的排序就是高级查询的一种,虽然从形式上我们是通过sort()方法实现的,但实质上MongoDB将其转发为了:find({'$query':queryDocObj,'$orderby':{key:1/-1}})
当然,高级查询肯定不可能单指排序,还有如下的查询选项,使用方式都和上边转化后的形式一样:
$maxscan:integer
指定查询最多扫描的文档数,最多从多少个文档中查询。
$min:document
查询开始的条件
$max:document
查询结束的条件
$hint:document
指定使用哪个索引进行查询
$explain:boolean
得到查询执行的细节(用到的索引,结果数量,耗时等)
$snapshot:boolean
确保查询的结果是在查询那一刻的一致快照。就是保证在整个查询周期中,不因为执行了insert、update等操作造成查询结果的不一致。
条件句与修改器的概念及区别
本文中多次提到了,类似于$not,$lt,$or这样的条件句,他们的结构和上一篇blog中介绍的update中$set,$pop等修改器一样。那么他们有什么区别呢。首先,用在查询中的叫条件句,用在更新中的叫修改器。其次,条件句是内层文档的key,而修改器是外层文档的key。例如:
修改器{'$set':{key:value}}
条件句${key:{'$lt':value}}
最后,一个key可以对应多个条件句,但是只能对应一个修改器。