MongoDB中使用find来进行查询。查询就是返回一个集合中文档的子集,子集的范围从0个文档到整个集合。find中的第一个参数决定了要返回的哪些文档,这个参数是一个文档,用于指定查询条件。javascript
空的查询文档(例如{})会匹配集合的所有内容。要不是指定查询文档,默认就是{}. 例如:java
> db.c.find()
将批量返回集合c中全部的文档。正则表达式
使用条件数据库
> db.users.find({"age": 27})
有时并不须要将文档中全部的键/值对都返回。遇到这种状况,能够经过find、findOne的第二参数来指定想要的键。这样作机会节省传输的数据量,又能节省客户端解码文档的时间和内存消耗。数组
例如,若是只对用户集合的“username”和"email"键感兴趣,可使用以下方式返回这些键:服务器
> db.users.find({}, {"username": 1, "email": 1})
这种状况默认"_id"这个键老是被返回的,即便没有指定要返回这个键。app
若是咱们不但愿结果中含有"fatal_weakness"键那么能够以下操做:函数
> db.users.find({}, {"username": 1, "_id": 0})
这样就能够把"_id"键剔除掉。post
当查询时,传递给数据库的查询文档的值必须是常量。也就是不能引用文档中其余键的值。例如保存库存有"in_stock"(剩余库存)和"num_sold"(已出售)两个键,想经过下列查询比较是行不通的。优化
> db.stock.find({"in_stock": "this.num_sold"})
"$lt","$lte","$gt"和"$gte"就是所有的比较操做符,分别对应<、<=、>、和>=。能够将其组合起来以便查找一个范围的值。例如查找18-30岁(含)的用户,就能够像下面这样
>db.users.find({"age": {"$gte": 18, "lte": 30}})
这样就能够找到"age"字段大于等于18,小于等于30的全部文档。
这样的范围查询对日期极为有用。例如要查找在2007年1月1日前注册的人,能够像下面这样。
> start = new Date("01/01/2007") > db.users.find({"registered": {"$lt": start}})
若是是想查询文档的某个键/值不等于某个特定值的状况下,就要使用另外一种条件操做符“$ne”,它表示不相等,如果想查询全部名字部位joe的用户,就能够以下查询
> db.users.find({"username": {"$ne": "joe"}})
MongoDB中有两种方式进行OR查询: "$in"能够用来查询一个键的多个值;"$or"更通用一些,能够在多个键中查询任意的给定值。
> db.raffle.find({"ticker_no": {"$in": [725, 542, 390]}})
"$in"很是灵活能够指定不一样类型的条件和值。例如,在逐步将用户的ID好前已成用户名的过程当中,查询须要同时匹配ID和用户名:
这会匹配"user_id"等于12345的文档,也会匹配"user_id"等于"joe"的文档。
要是"$in"对应的数组只有一个值,那么和直接匹配这个值的效果同样例如 {ticket_no: {"$in": [725]}} 和 {"ticker_no": 725} 效果同样。
与"$in"相对的是"$nin","$nin"将返回与数组中全部的条件都不匹配的文档好比:
> db.raffle.find({"ticket_no": {"$nin": [725, 543, 490]}})
"$in"能够对单个键作OR 查询,但想要找到"ticket_no"为725或者"winner"为true的文档应该怎么办呢?对于这种状况可使用 $or
> db.raffle.find({"$or": [{"ticket_no": 725}, {"winner": true}]})
还能够这样使用:
> db.raffle.find({"$or": [{"ticket_no": {"$in": [725, 345, 789]}},{"winner": true}]})
"$not"是元条件语句,便可以用在任何其余条件之上。就拿取模运算符"$mod"来讲。"$mod"会将查询的值除以第一个给定值,若余数等于第二个给定值则匹配成功:
> db.users.find({"id_num": {"$mod: [5, 1]}})
上面的查询会返回"id_num"值为1,6,11,16等用户。可是要想返回"id_num"为二、三、四、五、七、八、九、10等用户就要使用"$not"了:
>db.users.find({"id_num": {"$not": {"$mod": [5, 1]}}})
若是比较一下更新修改器和前面的查询文档,就会发现以$开头的键位于在不一样的位置。在查询中,"$lt"在内层文档,而更新中"$inc"则是外层文档的键。基本能够确定:条件语句是内层文档的键,而修改器则是外层文档的键。
能够对一个键应用多个条件。例如,要查找年龄为20~30的全部用户,能够在"age"键上使用"$gt"和"$lt":
> db.users.find({"age": {"$lt": 30, "$gt": 20}})
一个键能够有任意多个条件,可是一个键不能对应多个修改器。例如,修改器文档不能勇士含有{"$inc": {"age": 1}, {"$set": {"age": 40}}},由于修改了"age"两次。可是对于查询条件句就没有这种限定。
有一些元操做符也位于外层文档中,好比"$and"、"$or"和"$nor"。他们的使用形式相似:
>db.users.find({"$and": [{"x": {"$lt": 1}}, {"x": 4}]})
这个会查询匹配哪些"x"字段的值小于1而且等于4的文档,虽然看起来是矛盾的,可是彻底是可能的,好比,若是"x"字段的值是这样的一个{"x": [0, 4]},那么这个文档就与查询条件匹配,可是查询优化器不会对"$and"进行优化,这与其余操做符不一样。若是把上面的查询改为下面这样,效率更加高
>db.users.find({"x": {"$lt": 1, "$in": [4]}})
在MongoDB中有一些在查询时会有特殊的表现
null类型的行为有点奇怪他能够匹配自身,因此有一个包含以下文档的集合:
> db.c.find() { "_id" : ObjectId("5cd17b2891b417d2e2ad7467"), "y" : null } { "_id" : ObjectId("5cd17b2891b417d2e2ad7468"), "y" : 1 } { "_id" : ObjectId("5cd17b2891b417d2e2ad7469"), "y" : 2 }
就能够按照预期的方式查询"y"键为null的文档:
> db.c.find({"y": null}) { "_id" : ObjectId("5cd17b2891b417d2e2ad7467"), "y" : null }
可是null不只会匹配某个键的值为null的文档,并且还会匹配不包含这个键的文档,因此这种匹配还会返回缺乏这个键的全部文档:
> db.c.find({"z": null}) { "_id" : ObjectId("5cd17b2891b417d2e2ad7467"), "y" : null } { "_id" : ObjectId("5cd17b2891b417d2e2ad7468"), "y" : 1 } { "_id" : ObjectId("5cd17b2891b417d2e2ad7469"), "y" : 2 }
若是仅想匹配键值为null的文档,既要检查该键的值是否为null,还要经过"$exists"判断这个键值是否是存在:
> db.c.find({"z": {"$in": [null], "$exists": true}})
由于没有 "$eq"因此使用"$in"效果是同样的
正则表达式能够灵活有效的匹配字符串。例如,想要查找全部名为Joe或者joe的用户,就可使用正则表达式执行不区分大小写的匹配:
> db.users.find({"name": /joe/i})
系统能够接受正则表达式的标志(i),可是不是必定要有。如今已经匹配了各类大小写组合形式的joe,若是还但愿匹配"joey"这样的值,那么能够稍微修改一下
> db.users.find({"name": /joe?/i})
正则表达式也能够匹配自身
查询数组与查询标量的值是同样的。例若有一个水果列表,以下所示:
> db.food.insert({"friut": ["apple", "banana", "peach"]})
下面查询:
> db.food.find({"friut": "banana"}) { "_id" : ObjectId("5cd17ef091b417d2e2ad746e"), "friut" : [ "apple", "banana", "peach" ] }
会成功匹配这个文档,好像咱们在查询一个不合法的文档: {"fruit": "apple", "fruit": "banana", "fruit": "peach"}
> db.food.find() { "_id" : ObjectId("5cd1800f91b417d2e2ad746f"), "fruit" : [ "apple", "banana", "peach" ] } { "_id" : ObjectId("5cd1800f91b417d2e2ad7470"), "fruit" : [ "apple", "kumquat", "orange" ] } { "_id" : ObjectId("5cd1800f91b417d2e2ad7471"), "fruit" : [ "cherry", "banana", "apple" ] }
咱们要找到既有"apple"又有"banana"的文档,可使用"$all"来查询:
> db.food.find({"fruit": {"$all": ["apple", "banana"]}}) { "_id" : ObjectId("5cd1800f91b417d2e2ad746f"), "fruit" : [ "apple", "banana", "peach" ] } { "_id" : ObjectId("5cd1800f91b417d2e2ad7471"), "fruit" : [ "cherry", "banana", "apple" ] }
若是想查询数组特定位置的元素,需使用key.index语法指定下标:
> db.food.find({"fruit.2": "peach"}) { "_id" : ObjectId("5cd1800f91b417d2e2ad746f"), "fruit" : [ "apple", "banana", "peach" ] }
“$size”对于查询数组来讲也很是有用。顾名思义,能够用它来查询特定长度的数组。例如:
> db.food.find({"fruit": {"$size": 3}}) { "_id" : ObjectId("5cd1800f91b417d2e2ad746f"), "fruit" : [ "apple", "banana", "peach" ] } { "_id" : ObjectId("5cd1800f91b417d2e2ad7470"), "fruit" : [ "apple", "kumquat", "orange" ] } { "_id" : ObjectId("5cd1800f91b417d2e2ad7471"), "fruit" : [ "cherry", "banana", "apple" ] }
获得一个长度范围内的文档是一种常见的查询。"$size"并不能与其余查询条件(“$gt”)联合使用,可是这用查询能够在文档中添加一个"size"字段来时间每次"$push", “size”字段就加一,以后能够对这个字段进行查询。
> db.food.update(criteria, {"$push": {"fruit": "strawbery"}, {"$inc": {"size": 1}}})
可是这种技巧不能和"$addToSet" 操做符同时使用
find的第二个参数是可选的,能够指定须要返回的键。这个特别的"$slice"操做符能够返回某个键匹配的数组元素的一个子集。
加入,假设如今有一个博客文章的文档,咱们但愿返回前十条评论能够这样作:
> db.blog.posts.findOne(criteria, {"comments": {"slice": 10}})
也能够返回后面10条评论,只要在查询条件中使用-10就能够了:
> db.blog.posts.findOne(criteria, {"comments": {"slice": -10}})
"$slice"也能够指定偏移值以及但愿返回的元素的数量,来返回元素集合中间位置的某些结果:
> db.blog.posts.findOne(criteria, {"comments": {"$slice": [23, 10]}})
这个操做会跳过前23个元素,返回第24~33个元素。若是数组不够33个元素,则返回第23个元素后面的全部元素。
若是知道元素的下标,那么"$slice"很是有用。可是有时咱们但愿返回与查询条件相匹配的任意一个数组元素。可使用$操做符获得一个匹配的元素。对于上面的博客文章示例,能够用以下的方式获得Bob的评论:
> db.blogs.find({"comments.name": "bob"}, {"comments.$": 1}) { "_id": ObjectId("dfadfafajkldflajdfk32230942903"), "comments" : { "name": "bob", "email": "bob@example.com", "content": "good post" } }
注意这样只会返回第一个匹配的文档。若是Bob在这篇博客文章下写过多条评论,只有“comments”数组中的第一条评论会被返回
文档中的标量(非数组元素)必须与查询条件中的每一条语句想匹配。例如,若是使用{"x": {"$gt": 10, "$lt": 20}}进行查询,只会匹配"x"键的值大于10 而且小于20的文档。可是,加入某个文档的"x"字段是一个数组,若是"x"键的某个一元素与查询条件的任意一条语句相匹配(查询条件中的每条语句能够匹配不一样的数组元素),那么这个文档也会被返回。
下面用一个例子来详细说明这种状况。假若有以下所示的文档:
> db.test.find() { "_id" : ObjectId("5cd2c18cb54d3c27ab3c6b37"), "x" : 5 } { "_id" : ObjectId("5cd2c18cb54d3c27ab3c6b38"), "x" : 15 } { "_id" : ObjectId("5cd2c18cb54d3c27ab3c6b39"), "x" : 25 } { "_id" : ObjectId("5cd2c18cb54d3c27ab3c6b3a"), "x" : [ 5, 25 ] }
若是但愿找到"x"键位于10和20之间的全部文档,直接想到的查询方式是使用
> db.test.find({"x": {"$lt": 20, "$gt": 5}}) { "_id" : ObjectId("5cd2c18cb54d3c27ab3c6b38"), "x" : 15 } { "_id" : ObjectId("5cd2c18cb54d3c27ab3c6b3a"), "x" : [ 5, 25 ] }
5和25都不位于10和20之间,可是这个文档也返回了,由于25与条件查询中的第一个语句(大于10)相匹配5与查询条件中的第二个语句(小于20)相匹配。
这使对数组使用范围查询没有用:范围会匹配任意多元素数组。有几种凡是能够获得预期的行为。
首先,可使用"$elemMatch"要求同时使用查询条件中的两个语句与一个数组元素比较,可是这个有一个问题,"elemMatch"不会匹配费数组元素:
> db.test.find({"x": {"elemMatch": {"$gt": 10, "$lt": 20}}}) >
不会和{"x": 15}相匹配了,由于只查询数组了。
若是当前查询的字段上建立过索引可使用min,max将查询条件遍历的索引范围限制为"$gt","$lt"的值:
> db.test.find({"x": {"$gt": 10, "$lt": 20}}).min({"x": 10}).max({"x": 20}) {"x": 15}
查询内嵌文档
简单的查询
>db.people.find({"name.first": "Joe", "name.last": "Schmoe"})
可是当文档结构变得更加复杂以后,内嵌文档的匹配须要一些技巧。例如假设有博客文章若干,要找到Joe发表的5分以上的评论。博客文章的结构以下例所示:
> db.blog.find() { "content": "...", "comments": [ { "author": "joe", "score": 3, "comment": "nice post" }, { "author": "mary", "score": 5, "comment": "terrible post" } ] }
直接用 > db.blog.find({"comments": {"author": "joe", "score": {"$gte": 5}}}) 也不行由于符合author条件的评论和score条件的评论可能不是同一条评论。也就是说,会返回刚才显示的那个文档,由于“author”: joe 在第一条评论中匹配了,"score": 6在第二条评论中匹配了
要准确的指定一组条件,而没必要指定每一个键,就须要使用"elemMatch".。
> db.blog.find("comments": {"$elemMatch": {"author": "joe", "score": {"$gte": 5}}})
可使用任何的JavaScript代码
> db.foo.find({"$where": function() { .... }})
若是函数返回true文档就做为结果集的一部分返回;若是为false就不返回。
限制返回结果的数量,忽略必定数量的结果以及排序,全部这些选项必定要在查询被发送到服务器以前指定。
先限制结果数量,可在find后使用limit函数,例如只返回3个结果,能够这样:
> db.c.find().limit(3)
要是匹配的结果不到三个,则返回匹配的数量。limit指定的是数量上限而非下限。
skip和limit类似
>db.c.find().skip(3)
上面的操做会略过前三个匹配的文档,而后返回余下的文档。若是集合里面能匹配的文档少于3个,则不会返回任何文档。
sort 接受一个对象做为参数,这个对象是一组键/值对,键对应文档的键名,只表明排序的方向。排序方向能够是1(升序)或者是-1(降序)。若是指定了多个键,则按照这些键被指定的顺序逐个排序,例如按照"username"升序及"age"降序排序,能够这样写:
>db.c.find().sort({"username": 1, "age": -1})
这三个方法能够组合使用。
对键的排序是有优先级的,顺序以下: