ITKeyword - 技术文章推荐分享

首页 > mongodb高级操作(2)-查询

mongodb高级操作(2)-查询

标签: mongodb, find,

相关推荐:MongoDB学习(3)高级操作

今天跟大家分享一下mongodb中比较好玩的知识,主要包括:聚合,游标。一: 聚合 常见的聚合操作跟sql server一样,有:count,distinct,group,mapReduce。<1> count count是最简单,最容易,也是最常用的聚合工具,它的使用跟我们C#里

1.查询文档find介绍mongodb中使用find来进行查询.find的第一个参数决定了要返回哪些文档,这个参数是一个文档,用于指定查询条件.如果不指定条件默认就是{},那么就是查询所有文档.> db.test.find(){ "_id" : ObjectId("573c858c323f7f2e2ccb0e17"), "name" : "brent", "age" : 43, "status" : "done" }{ "_id" : ObjectId("573c86d3017c5eb7d08aed6d"), "name" : "bob", "age" : 1, "status" : "done" }{ "_id" : ObjectId("573c88fe017c5eb7d08aed6e"), "name" : "tom", "age" : 10, "status" : "done" }{ "_id" : ObjectId("573c8bd3323f7f2e2ccb0e18"), "name" : "brent", "age" : 30, "status" : "done" }向查询中指定键值,意味着限定查询条件,查询简单的类型只要指定要查找的值就行了:> db.test.find({"name":"brent"}){ "_id" : ObjectId("573c858c323f7f2e2ccb0e17"), "name" : "brent", "age" : 43, "status" : "done" }{ "_id" : ObjectId("573c8bd3323f7f2e2ccb0e18"), "name" : "brent", "age" : 30, "status" : "done" }可以在查询中指定多个键值对,以逗号隔开,这样的意思是条件1 AND 条件2 AND ....的意思:> db.test.find({"name":"brent","age":43}){ "_id" : ObjectId("573c858c323f7f2e2ccb0e17"), "name" : "brent", "age" : 43, "status" : "done" }指定返回的键有时并不是需要返回所有的键,这时可以通过指定find或者findOne的第二个参数来指定想要的键,例如只想查询"name"为"brent"的name和age键:> db.test.find({"name":"brent"},{"name":1,"age":1}){ "_id" : ObjectId("573c858c323f7f2e2ccb0e17"), "name" : "brent", "age" : 43 }{ "_id" : ObjectId("573c8bd3323f7f2e2ccb0e18"), "name" : "brent", "age" : 30 }默认情况下_id都是会返回的,也可以使用第二个参数来剔除某个键,例如我们不希望得到status的键:> db.test.find({"name":"brent"},{"status":0}){ "_id" : ObjectId("573c858c323f7f2e2ccb0e17"), "name" : "brent", "age" : 43 }{ "_id" : ObjectId("573c8bd3323f7f2e2ccb0e18"), "name" : "brent", "age" : 30 }使用这种方法还可以将_id列剔除:> db.test.find({"name":"brent"},{"status":0,"_id":0}){ "name" : "brent", "age" : 43 }{ "name" : "brent", "age" : 30 }限制查询传递的参数必须是常量,例如如果想查询一个文档中的某两个列相等的情况是不行的.2.查询条件查询除了上面简单介绍的精确匹配,还有更加复杂的查询,比如范围查询,or,and,取反等等查询条件"$lt","$lte","$gt","$gte"就是全部的比较操作符.分别对应着<,<=,>和>=,可以将这些组合起来以便查找一个范围的值.例如下面的例子查找age大于20小于30的文档:> db.test2.find(){ "_id" : ObjectId("573e72449e178b5475b29d89"), "name" : "brent", "age" : 28 }{ "_id" : ObjectId("573e73149e178b5475b29d8a"), "name" : "brent", "age" : 10 }{ "_id" : ObjectId("573e73ae9e178b5475b29d8b"), "name" : "bob", "age" : 14 }> db.test2.find({"age":{"$gt":20,"$lt":30}}){ "_id" : ObjectId("573e72449e178b5475b29d89"), "name" : "brent", "age" : 28 }对于文档的键值不等于某个特定的值,就要使用"$ne"了,他表示不相等.下面例子要查找name不等于brent的用户:> db.test2.find({"name":{"$ne":"brent"}}){ "_id" : ObjectId("573e73ae9e178b5475b29d8b"), "name" : "bob", "age" : 14 }OR查询有两种方式进行OR查询:"$in"可以用来查询一个键的多个值,"$or"可以在多个键中查询任意给定的值.例如下面要查询age为10,14的文档:> db.test2.find({"age":{"$in":[10,14]}}){ "_id" : ObjectId("573e73149e178b5475b29d8a"), "name" : "brent", "age" : 10 }{ "_id" : ObjectId("573e73ae9e178b5475b29d8b"), "name" : "bob", "age" : 14 }使用"$in"的时候,可以指定不同类型的条件和值,如果"$in"的数组只有一个值,那么和直接匹配是一样的."$in"和"nin"是相对的,"nin"返回数组中不匹配的文档.查询age不为10,14的文档:> db.test2.find({"age":{"$nin":[10,14]}}){ "_id" : ObjectId("573e72449e178b5475b29d89"), "name" : "brent", "age" : 28 }"$in"只能对单个键做OR查询,如果想对多个键做匹配OR查询那么可以使用"$or","$or"接受一个包含所有可能的数组作为条件.例如下面这个查询name为bob或者age为10的文档:> db.test2.find({"$or":[{"name":"bob"},{"age":10}]}){ "_id" : ObjectId("573e73149e178b5475b29d8a"), "name" : "brent", "age" : 10 }{ "_id" : ObjectId("573e73ae9e178b5475b29d8b"), "name" : "bob", "age" : 14 }还可以将"$or"和"in"联合起来使用:> db.test2.find({"$or":[{"age":{"$in":[10,28]}},{"name":"bob"}]}){ "_id" : ObjectId("573e72449e178b5475b29d89"), "name" : "brent", "age" : 28 }{ "_id" : ObjectId("573e73149e178b5475b29d8a"), "name" : "brent", "age" : 10 }{ "_id" : ObjectId("573e73ae9e178b5475b29d8b"), "name" : "bob", "age" : 14 }$not"$not"是元条件句,即可应用于任何其它条件之上,拿"$mod"来说,"$mod"会查询的值除以第一个给定的值,若余数等于第二个值则匹配成功例如find({"id":{"$mod":[5,1]}})会匹配到1,6,11,16...的数,但是如果你要匹配2,3,4,5,7,8,9这些数就可以使用"$not"find({"id":{"$not":{"$mod":[5,1]}}})3.特定类型的查询null类型null类型可以匹配本身,而且会匹配不包含这个键的文档,所以这种匹配还会返回缺少这个键的文档.先在集合中插入一个name为null的文档> db.test2.insert({"name":null})WriteResult({ "nInserted" : 1 })> db.test2.find(){ "_id" : ObjectId("573e72449e178b5475b29d89"), "name" : "brent", "age" : 28 }{ "_id" : ObjectId("573e73149e178b5475b29d8a"), "name" : "brent", "age" : 10 }{ "_id" : ObjectId("573e73ae9e178b5475b29d8b"), "name" : "bob", "age" : 14 }{ "_id" : ObjectId("573e80569e178b5475b29d8c"), "name" : null }试着查找name为空的文档,可以匹配,如果查找没有的键job,那么会匹配所有的文档:> db.test2.find({"name":null}){ "_id" : ObjectId("573e80569e178b5475b29d8c"), "name" : null }> db.test2.find({"job":null}){ "_id" : ObjectId("573e72449e178b5475b29d89"), "name" : "brent", "age" : 28 }{ "_id" : ObjectId("573e73149e178b5475b29d8a"), "name" : "brent", "age" : 10 }{ "_id" : ObjectId("573e73ae9e178b5475b29d8b"), "name" : "bob", "age" : 14 }{ "_id" : ObjectId("573e80569e178b5475b29d8c"), "name" : null }如果仅仅想要匹配键值为null的文档,既要检查改键值是否为null,还要通过"$exists"条件判断键值已存在> db.test2.find({"job" : {"$in":[null],"$exists":true}})正则表达式正则表达式能够灵活的匹配字符串,mongodb使用perl的正则表达式pcre库来匹配正则表达式.建议在查询前现在shell中检查一下语法,确保匹配与设想的一致.例如下面匹配不区分大小写的bob文档:> db.test2.find({"name":/bob/i}){ "_id" : ObjectId("573e73ae9e178b5475b29d8b"), "name" : "bob", "age" : 14 }{ "_id" : ObjectId("573e853c9e178b5475b29d8d"), "name" : "BOB" }查询数组$all查询数组元素与查询标量值是一样的,例如有下面一个集合:> db.test3.find(){ "_id" : ObjectId("573e874c9e178b5475b29d8e"), "name" : "brent", "fav" : [ "game", "film", "read" ] }{ "_id" : ObjectId("573e87849e178b5475b29d8f"), "name" : "bob", "fav" : [ "drink", "football", "runing" ] }{ "_id" : ObjectId("573e87cc9e178b5475b29d90"), "name" : "jack", "fav" : [ "read", "basketball", "drink" ] }查询fav为drink的文档,它会成功匹配所有fav中包含drink的文档:> db.test3.find({"fav":"drink"}){ "_id" : ObjectId("573e87849e178b5475b29d8f"), "name" : "bob", "fav" : [ "drink", "football", "runing" ] }{ "_id" : ObjectId("573e87cc9e178b5475b29d90"), "name" : "jack", "fav" : [ "read", "basketball", "drink" ] }如果需要通过多个元素来匹配数组,那么就要使用"$all"了,这样就会匹配一组元素,下面例子匹配fav中包含drink和read的文档> db.test3.find({"fav":{"$all":["drink","read"]}}){ "_id" : ObjectId("573e87cc9e178b5475b29d90"), "name" : "jack", "fav" : [ "read", "basketball", "drink" ] }这里的顺序无关紧要.还可以对数组进行精确匹配,精确匹配需要数组完全一致,不能有缺少和冗余的元素,而且顺序也一定要一致,例如下面的例子:> db.test3.find({"fav":["drink"]})> db.test3.find({"fav":["drink","running","football"]})> db.test3.find({"fav":["drink","football","runing"]}){ "_id" : ObjectId("573e87849e178b5475b29d8f"), "name" : "bob", "fav" : [ "drink", "football", "runing" ] }要想插叙数组特定位置的元素,需要使用key.index的语法指定下标,例如查找fav第二个元素为film的文档,注意index是从0开始的:> db.test3.find({"fav.1":"film"}){ "_id" : ObjectId("573e874c9e178b5475b29d8e"), "name" : "bre

相关推荐:MongoDB高级查询[聚合Group]

转自:http://my.oschina.net/zhzhenqin/blog/99846Group为了方便我还是把我的表结构贴上来:和数据库一样group常常用于统计。MongoDB的group还有很多限制,如:返回结果集不能超过16M, group操作不会处理超过10000个唯一键,好

nt", "fav" : [ "game", "film", "read" ] }$size"$size"用来查询数组的长度.例如查找fav长度为2的文档:> db.test3.find({"fav":{"$size":2}}){ "_id" : ObjectId("573e8b719e178b5475b29d91"), "name" : "tom", "fav" : [ "chess", "cooking" ] }"$size"不能与其它的查询条件组合使用,例如"%gt"$slice操作符find的第二个参数返回指定的键.这个特别的"$slice"操作符可以返回某个键匹配的数组元素的一个子集.例如我想返回前2个fav的值:> db.test3.findOne({"name":"brent"},{"fav":{"$slice":2}}){ "_id" : ObjectId("573e874c9e178b5475b29d8e"), "name" : "brent", "fav" : [

"game",

"film" ]如果想要返回后2个的值,就写-2就可以了."$slice"也可以指定偏移量和返回的元素数量,例如:> db.test3.findOne({"name":"brent"},{"fav":{"$slice":[1,2]}}){ "_id" : ObjectId("573e874c9e178b5475b29d8e"), "name" : "brent", "fav" : [

"film",

"read" ]}这表示跳过前面1个,从第二个开始返回两个元素,如果元素不够则返回所有的元素.除非特别声明,否则使用"$slice"将返回文档中的全部键.返回一个匹配的数组元素如果知道元素的下标,那么"$slice"非常有用,如果想返回与查询条件相匹配的任意数组元素,使用$操作符 .例如下面得到name为bob的,并且显示任意一个评论:> db.test4.findOne(){ "_id" : ObjectId("573f390c9e178b5475b29d92"), "name" : "brent", "comment" : [

{

"name" : "bob",

"content" : "good"

},

{

"name" : "jack",

"content" : "repost"

} ]}> db.test4.find({"comment.name":"bob"},{"comment.$":1}){ "_id" : ObjectId("573f390c9e178b5475b29d92"), "comment" : [ { "name" : "bob", "content" : "good" } ] }数组和范围查询的相互作用如果文档中的某一个字段是一个数组,而这时使用范围查询的匹配,例如"$gt","$lt",那么只要数组中的任意一个元素与之匹配,则也会返回.例如当我们想找到10<x<20的文档的时候,有一个文档的x是一个数组有两个值[5,25],那么这个文档将也会被匹配,这是因为5是<20,而25>10所以满足10<x<20,虽然并不是任意一个元素都满足此条件.有几种方法可以避免这个问题.可以使用"$elemMatch",要求mongodb同时使用查询条件中的两个语句与一个数组元素进行比较,但是"$elemMatch"不会匹配非数组元素.> db.test.find({"x":{"$elemMatch":{"$gt":10,"$lt",20}}})如果当前查询的字段上创建有索引,可以使用min()和max()将查询条件比例的索引范围限制为"$gt"和"$lt"的值:> db.test.find({"x":{"$gt":10,"$lt":20}}).min({"x":10}).max({"x":20})查询内嵌文档查询内嵌文档可以使用.键的方式查询,例如下面这个文档> db.test5.findOne(){ "_id" : ObjectId("5740142abc583612a8464117"), "name" : {

"first" : "kevin",

"last" : "love" }}如果要查询name为kevin love的人:> db.test5.find({"name.first":"kevin","name.last":"love"}){ "_id" : ObjectId("5740142abc583612a8464117"), "name" : { "first" : "kevin", "last" : "love" } }4.$where查询使用"$where"子句,可以在查询中执行任意的javascript.这样就能在查询中做几乎任何事情,为了安全,应该严格限制或者消除"$where"语句的使用"$where"最为常用的应用就是比较文档中的两个键是否相等.不是非常必要的时候不要使用"$where",因为速度上比常规的查询要慢很多,而且无法使用索引,每个文档都要从bson转换成javascipt对象,然后通过"$where"来运行.在服务器上使用javascipt的时候需要注意,如果使用不当服务器端javascript很容易收到注入攻击.可以在mongod启动的时候指定--noscripting选项5.游标数据库使用游标返回find的结果.客户端对游标的实现通常能够对最终结果进行有效的控制.要想从shell中创建游标,先对其查询,然后将结果分配给一个局部变量.> for(i=0;i<100;i++){... db.t1.insert({x:i})... }WriteResult({ "nInserted" : 1 })> var cur=db.t1.find()这样的好处是可以一次查看一条结果,如果结果没有房子变量中,mongodb shell就会自动迭代(测试发现shell会每次显示20条结果).而我们要迭代结果,可以使用next方法,也可以使用hasNext来查看游标中是否还有其它结果.> while(cur.hasNext()){... obj=cur.next();... }{ "_id" : ObjectId("57401df5bc583612a846417b"), "x" : 99 }游标还实现了javascript的迭代器接口,可以在forEach循环中使用:> var cur=db.t1.find()> cur.forEach(function(x){... print(x.name);... });调用find的时候,shell并不立刻查询数据库,耳塞等待真正开始要求获得结果的时候才发送查询,几乎所有的游标对象的方法都返回游标笨死,这样就可以按照任意顺序组成方法链.所以下面的几个表达式是相同的:> var cur=db.t1.find().sort({"x":1}).limit(1).skip(10);> var cur=db.t1.find().limit(1).sort({"x":1}).skip(10);> var cur=db.t1.find().skip(10).limit(1).sort({"x":1});limit,skip和sort最常用的查询选项就是限制返回的结果数量,忽略一定的数据的结果和排序.要限制数量结果,在find后面使用limit函数,例如要返回3条结果可以这样使用:> db.t1.find().limit(3){ "_id" : ObjectId("57401df5bc583612a8464118"), "x" : 0 }{ "_id" : ObjectId("57401df5bc583612a8464119"), "x" : 1 }{ "_id" : ObjectId("57401df5bc583612a846411a"), "x" : 2 }skip与limit类似,skip(99)会跳过前99条文档,然后返回余下的文档> db.t1.find().skip(99){ "_id" : ObjectId("57401df5bc583612a846417b"), "x" : 99 }sort接受一个对象作为参数键对应键名,值代表排序方向,1为升序,-1为降序,如果指定多个键,则按照键的指定顺序逐个排序,例如:> db.test2.find().sort({"name":1,"age":-1}){ "_id" : ObjectId("573e80569e178b5475b29d8c"), "name" : null }{ "_id" : ObjectId("573e853c9e178b5475b29d8d"), "name" : "BOB" }{ "_id" : ObjectId("573e73ae9e178b5475b29d8b"), "name" : "bob", "age" : 14 }{ "_id" : ObjectId("573e72449e178b5475b29d89"), "name" : "brent", "age" : 28 }{ "_id" : ObjectId("573e73149e178b5475b29d8a"), "name" : "brent", "age" : 10 }我们发现null是默认是排在升序的第一个,而如果指定的键没有的话是也是排在上面的.这三个方法可以组合起来使用.这对于分页非常有用.例如想要看一个商品mp3的前50名按照价格从高到低排序:> db.stock.find({"desc":"mp3"}).limit(50).sort({"price":-1})然后查看下面50条的时候可以使用skip跳过前50条即可:> db.stock.find({"desc":"mp3"}).limit(50).sort({"price":-1}).skip(50)然而过多的过滤会影响性能.mongodb在比较不同类型是有一定顺序的,有时一个键有多个类型,那么进行排序的时候是安装类型的优先级进行的.例如上面我们就发现null的优先级就比较低.下面是优先级的从小到大排序:(1)最小值;(2)null;(3)数字(整形,长整形,双精度);(4)字符串(5)对象/文档(6)数组(7)二进制数据(8)对象ID(9)布尔型(10)日期型(11)时间戳(12)正则表达式(13)最大值避免使用skip略过大量结果使用skip跳过大量数据的时候,需要先找到被略过的数据,再进行抛弃,如果数量非常大的话,效率是非常低的,速度会变得很慢.1.不用skip对结果分页前面我们已经讲了分页的方法.先使用limit再使用skip跳过前一次的limit的结果.然而我们可以找到另外的方法进行排序.例如上面的例子查找MP3价格的前50条,我们可以使用下面的语句先找出前50的价格.>var page1=db.stock.find({"desc":"mp3"}).limit(50).sort({"price":-1})然后利用最后一个文档中的price作为条件获取下一页,即比最后一个文档中的price更低的价格.显示最后一页:while(page1.hasNext()){latest=page1.next();display(latest)}那么下一页就是价格比latest.price更小的50个文档:var page2=db.stock.find({"price":{"$lt":latest.price}});pages.sort({"price":1}).limit(100);这样查询中就没有skip了.2.随机选取文档可以利用Math.random()产生一个随机数(0-1),在创建文档时候添加一个随机列,在查询的时候使用random来进行"$lt"或者"$gt"进行匹配.高级查询选项有两张类型的查询:简单查询和封装查询.简单查询就像普通的:> db.test2.find({"name":"brent"})有一些的选择可以用于对查询的封装,例如:> db.t1.find({"name":"brent"}).sort({"x":1})实际的查询是先将查询封装在一个更大的文档中,shell会把查询从{"name":"brent"}转换成{"$query":{"name":"brent"},"$orderby":{"x":1}}绝大多数驱动程序提供了辅助函数,用于向查询中添加各种选项,下面列举了其它一些有用的选项:"$maxscan":integer指定本次查询中扫描文档数量的上限.> db.t1.find()._addSpecial("$maxscan",1)"$min":document指定查询的开始条件,查询会强制使用索引,而且强制扫描索引的下边界.这在复杂查询中很有用"$max":document同理如上.强制使用索引,并指定扫描索引的上边界."$showDiskLoc:true在查询结果中添加一个"$showdiskLoc"字段用于显示该条结果在磁盘上的位置 > db.test2.find()._addSpecial("$showDiskLoc",true){ "_id" : ObjectId("573e72449e178b5475b29d89"), "name" : "brent", "age" : 28, "$recordId" : NumberLong(1) }{ "_id" : ObjectId("573e73149e178b5475b29d8a"), "name" : "brent", "age" : 10, "$recordId" : NumberLong(2) }{ "_id" : ObjectId("573e73ae9e178b5475b29d8b"), "name" : "bob", "age" : 14, "$recordId" : NumberLong(3) }{ "_id" : ObjectId("573e80569e178b5475b29d8c"), "name" : null, "$recordId" : NumberLong(4) }{ "_id" : ObjectId("573e853c9e178b5475b29d8d"), "name" : "BOB", "$recordId" : NumberLong(5) }显示记录的ID.6.数据库命令在数据库操作,管理以及监控中,数据库命令都是非常有用的.例如删除集合使用"drop"数据库命令完成.> db.runCommand({"drop":"t1"}){ "ns" : "suq.t1", "nIndexesWas" : 1, "ok" : 1 }也许你对shell辅助函数比较熟悉,其实这些辅助函数就是 封装的数据库命令,例如上面的数据库命令也可以使用db.t1.drop()完成.在shell中运行db.listCommands()查看所有的数据库命令数据库命令总是会返回一个包含ok键的文档,如果ok为1说明命令执行成功,如果为0则说明命令执行失败.如果返回的是0,则还有一个额外的errmsg键,它描述命令执行失败的原因,例如下面再次运行drop命令:> db.runCommand({"drop":"t1"}){ "ok" : 0, "errmsg" : "ns not found", "code" : 26 }runCommand命令其实等价于执行一个为$cmd的文档的查询,例如上面的命令等价于:> db.$cmd.findOne({"drop":"t1"}){ "ok" : 0, "errmsg" : "ns not found", "code" : 26 }只是这个查询在mongodb内部会进行特殊的处理,几乎所有的Mongodb驱动程序都会提供一个类似runCommand的辅助函数.有些命令需要管理员权限才能执行,而且有的需要在admin数据库上才能执行.如果当前位于其它数据库,但是需要执行一个管理员命令,可以使用adminCommand而不是runCommand:> db.adminCommand({shutdown:1})2016-05-21T21:28:43.942+0800 E QUERY

[thread1] Error: error doing query: failed: network error while attempting to run command 'shutdown' on host '127.0.0.1:27017'

:DB.prototype.runCommand@src/mongo/shell/db.js:135:1DB.prototype.adminCommand@src/mongo/shell/db.js:153:16@(shell):1:1 2016-05-21T21:28:43.943+0800 I NETWORK

[thread1] trying reconnect to 127.0.0.1:27017 (127.0.0.1) failed2016-05-21T21:28:43.944+0800 W NETWORK

[thread1] Failed to connect to 127.0.0.1:27017, reason: errno:111 Connection refused2016-05-21T21:28:43.944+0800 I NETWORK

[thread1] reconnect 127.0.0.1:27017 (127.0.0.1) failed failed 另外注意mongodb中的数据库命令与字段顺序是有关的.命令名称必须是第一个字段.!

相关推荐:mongodb高级操作(1)-update

前面我们已经介绍了mongodb的基本操作:mongodb基本操作下面是介绍一些高级的增删改查操作.1.更新文档文档替换最简单的方法就是文档完全替换,如下就是一个完全替换的例子,先把需要更新的文档找出来并且赋值,然后修改所赋的值,最后再进行update

1.查询文档find介绍mongodb中使用find来进行查询.find的第一个参数决定了要返回哪些文档,这个参数是一个文档,用于指定查询条件.如果不指定条件默认就是{},那么就是查询所有文档.>...

------分隔线----------------------------