设为首页 收藏本站
查看: 1331|回复: 0

[经验分享] MongoDB的条件查询

[复制链接]

尚未签到

发表于 2015-7-7 09:18:12 | 显示全部楼层 |阅读模式
  有段时间没看书了,记录下这个周末看《MongoDB权威指南》的笔记,目前看到是第四章:查询



Java代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf DSC0000.png

  • find({查询条件限定},{返回字段})  
  这是一个查询的基本语法,各个签名的作用已经说得很清楚。下面来细细展开:
  当然最开始插入一批数据以供测试:



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • db.users.insert({"_id": 1, "name": "aroba", "age": 22, "friends": 3})  
  • db.users.insert({"_id": 2, "name": "brob", "age": 23, "friends": 4})  
  • db.users.insert({"_id": 3, "name": "robin", "age": 24, "friends": 23})  
  • db.users.insert({"_id": 4, "name": "ccrob", "age": 25, "friends": 32})  
  • db.users.insert({"_id": 5, "name": "drobin", "age": 26, "friends": 15})  
  • db.users.insert({"_id": 6, "name": "rrobin", "age": "az", "friends": 19})  
  
  1、 方法中的第一个参数:查询条件限定是一个document结构,如为{}将默认返回所有数据



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • #查询一个年龄为27的用户:  
  • db.users.find({"age":23})  
  • #查询一个年龄为27,姓名为robin的用户,相当于AND  
  • db.users.find({"age":23, "name":"brob"})  
  作为文档的查询条件,可以支持更复杂的格式:



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • #查询年龄大于20且小于30的用户  
  • db.users.find({"age":{"$gt":20, "$lte":23}})  
  这里条件查询有常用的:小于("$lt")、小于等于("$lte")、大于("$gt")、大于等于("$gte")、不等于("$ne") 。这些条件查询对数字日期类型的字段比较适用
  
  前面说到同时查询age和name属性,相当于AND查询。这里来看看OR查询,主要通过"$in"和"$or" 。对单一键有多个值与其匹配的话就用"$in",后面跟一个条件数组。



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • #查询年龄在某个范围的用户:  
  • db.users.find({"age":{"$in":[20, 22, 25]}})  
  "$in" 对支持的类型非常灵活,不同类型的条件可以同时查询。与之相对应的就是"$nin",表示不在该范围内的键



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • db.users.find({"age":{"$in":[20, 22, 25, "az"]}})  
  • db.users.find({"age":{"$nin":[20, 22, 25, "az"]}})  
  与单一键的"$in"不同的是,"$or"是包含多个可能条件的数组。



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • #年龄在某个范围内或者name在某个范围内的用户  
  • db.users.find({"$or": [{"age": 23 }, {"name": "robin"}]})  
  • db.users.find({"$or": [{"age": {"$in": [ 23, 4, "az" ]} }, {"name": "robin"}]})  
  
  2、返回字段
  作为查询的第二个参数,如果没有的话是默认返回所有字段。可以对需要的返回字段指定:



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • db.users.find({}, {"name":1, "age":1})  
  1、这个查询会返回name、age、_id字段
2、_id是默认返回,如果不要显示加上("_id":0)



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • db.users.find({}, {"name":1, "age":1, "_id":0})  
  3、如果某个字段如age不存在,也不抛异常
4、需要显示的字段设置为大于零的数就可以,但还是用1好理解,但如果对不需要显示的字段且不是_id设置为0或其他会抛异常



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • db.users.find({}, {"name":1, "age":0, "_id":0})  
  这样是不行的,如果不要返回age不加上就可以了
  后面还将对数组查询的返回字段做相应的说明,这里就先到此
  
  3、几点说明
  1、"$not"元条件句,用在其他任何条件上,如



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • #age>20即查询age小于等于20的用户  
  • db.user.find({"age": {"$not" : {"$gt" :20}}})   
  • #这里查询age不是1,6,11,16...等的用户  
  • db.user.find({"age": {"$not": {"$mod": [5, 1]}}})   
  
  2、条件查询与更新修改器



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • #更新修改器  
  • db.users.update({"age": 23},{"$set":{"name":"zzzz"}})  
  • #条件查询  
  • db.users.find({"age": {"$gt": 20}})   
  条件句是内层文档键,修改器是外层文档键。而且对同一个字段age来说可以是多个限定条件,但是修改器不能对应多个
  
  3、null
如果某个字段的值为null,根据null来查询时可以返回该条文档,但也会返回不包含该字段的文档



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • #新增两条数据  
  • >db.users.insert{ "_id" : 7, "age" : 23, "name" : "joe" }  
  • >db.users.insert{ "_id" : 8, "age" : 24, "friends" : null, "name" : "sam" }  
  查询键值为null的字段



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • >db.users.find({"friends": null})。  
  这里会返回friends为null的文档,但是也会返回没有该键的文档
  



Shell代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • { "_id" : 7, "age" : 23, "name" : "joe" }  
  • { "_id" : 8, "age" : 24, "friends" : null, "name" : "sam" }  
  需要通过"$exists"来判定键值是否存在



Shell代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • > db.users.find({"friends":{"$in":[null],"$exists":true}})  
  • { "_id" : 8, "age" : 24, "friends" : null, "name" : "rrbin" }  
  
  4、正则表达式



Shell代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • #这里会返回所有name中包含rob字段的文档  
  • > db.users.find({"name":/rob/})  
  • #不仅对字段值进行正则匹配,如果值本身是正则式也匹配  
  
  
  4、数组查询
  插入几条数据测试



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • db.food.insert({"_id": 1, "fruit": ["apple", "banana", "peach"]})  
  • db.food.insert({"_id": 2, "fruit": ["apple", "orange"]})  
  • db.food.insert({"_id": 3, "fruit": ["banana", "peach", "orange"]})  
  以下是一些常用的查询方法,直接上



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • #匹配fruit中包含banana的文档  
  • db.food.find({"fruit": "banana"})  
  • #必须匹配所有  
  • db.food.find({"fruit": {"$all" : ["apple", "peach"]}})  
  • #精确匹配  
  • db.food.find({"fruit": ["apple", "orange"]})  
  • #指定下标 key.index  
  • db.food.find({"fruit.2": "peach"})  
  • #查询指定长度的数组  
  • db.food.find({"fruit": {"$size" : 3}})  
  但是"$size"操作只能严格匹配,遇到比如要求数组大于或者小于之类的查询就无能为力了。这里提供了解决的方案:对文档新增size字段,每次对数组push或pop操作时,对size字段做相应的增减。查询的时候再对字段size做相应的处理



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • db.food.update({"$push" :{"fruit" : "strawberry"} , "$inc" : {"size" : 1}})  
  • db.food.find({"size" : {"$gt" : 3}})  
  
  返回数组指定子集
"$slice"用于返回数组的一个子集,支持前、后或者偏移



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • db.food.insert({"_id": 4, "fruit": ["apple", "banana", "peach", "orange", "watermelon", "lemon", "cherry"]})  
  • #取前2个  
  • db.food.find({"_id":4}, {"fruit":{"$slice":2}})  
  • #{u'_id': 4, u'fruit': [u'apple', u'banana']}  
  • #取后两个  
  • db.food.find({"_id":4}, {"fruit":{"$slice":-2}})  
  • #{u'_id': 4, u'fruit': [u'lemon', u'cherry']}  
  • #从第2个开始取三个,这个其实达到分页的效果,但书中明确指出对大量数据skip性能下降厉害,不建议考虑这种方式  
  • db.food.find({"_id":4}, {"fruit":{"$slice":[2, 3]}})  
  • #{u'_id': 4, u'fruit': [u'peach', u'orange', u'watermelon']}  
  使用"$slice"获取数组内的值时,其他的键也会默认返回,如果不需要返回非数组内的其他键这里可以指明,与前面返回不同的是这里可以用0



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • db.food.insert({"_id": 5, "sum":7, "fruit": ["apple", "banana", "peach", "orange", "watermelon", "lemon"]})  
  • db.food.find({"_id":5}, {"fruit":{"$slice":[2, 3]}, "_id":0, "sum":0})  
  • {u'fruit': [u'peach', u'orange', u'watermelon']}  
  
  5、查询内嵌文档
  这里主要考虑匹配查询内嵌文档,考虑如下文档



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • db.users.insert({"_id": 9, "age":23, "name": {"first":"joe", "last":"sam"}})  
  • db.users.insert({"_id": 10, "age":24, "name": {"first":"joe", "middle":"dd", "last":"sam"}})  
  查询名字为joe sam的用户



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • #查询名字为joe sam的用户  
  • data = db.users.find({"name":{"first":"joe", "last":"sam"}})  
  • #返回第一条,实际上这相当于精确匹配,这个查询条件将严格匹配顺序、字段的数量。其实第二条也是我们想要的结果,那么正确的写法应该是:  
  • data = db.users.find({"name.first":"joe", "name.last":"sam"})  
  书中说到一种复杂情况下的查询:joe发表的5分以上的评论:



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • db.blog.insert({"_id":1, "content":"....", "comments":[{"name":"joe", "score":3, "comment":"nice"}, {"name":"sam", "score":5, "comment":"zzz"}, {"name":"joe", "score":5, "comment":"good"}]})  
  • data = db.blog.find({"comments":{"name":"joe", "score":{"$gte":5}}})  
  • #这样是查不到数据的,内嵌文档要求匹配整个文档,而不是comments键  
  • data = db.blog.find({"comments.name":"joe", "comments.score":{"$gte":5}})  
  • #这个查询会返回这条记录,其实是匹配的commets中各个键,即joe匹配第一条,score匹配第二条  
  • data = db.blog.find({"comments":{"$elemMatch":{"name":"joe", "score":{"$gte":5}}}})  
  
  
  6、分页
  分页在前面说到"$slice"时,其实是达到分页的效果,前面也说了弊端,这里进一步说明。这里采用limit限制返回结果,slice跳过指定数量文档,sort对查询结果排序
  limit
db.users.find().limit(3)结果集超过三条返回三条,不足返回实际数量,貌似对负数不感冒,比如-2还是返回前两条,或者limit里没有偏移这个概念
skip
db.users.find().limit(3)省略结果集前三个,返回剩下的,结果集不足三个就啥都木有了,当然这个也一样,别写负数了,否则抛异常
sort
对结果集排序:1升序,-1降序。可支持多个键/对



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • db.users.find().sort([("name", 1), ("age", -1)])  



Shell代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • db.users.find().sort({"name":1,"age":-1})  



Python代码 http://mj4d.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf

  • #这就是分页  
  • db.users.find().limit(2).sort("_id", 1)  
  • db.users.find().limit(2).skip(2).sort("_id", 1)  
  • db.users.find().limit(2).skip(4).sort("_id", 1)  
  这对大数据量的skip性能影响较大,这里也提供了一些绕过的方法。比如先取得最后一条的记录的某个唯一键,再查询大于该键的值。可以看出这个限制条件挺多,当然容易想到的采用主键"_id",这是主键必须是数字了
  
  
  书中还说到了其他的一些高级特性,如$where、随机获取、包装查询、获取一致性结果等,这里就没记录下来

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-83996-1-1.html 上篇帖子: 关于MongoDb Replica Set的故障转移集群——实战篇 下篇帖子: MongoDB分片实战(三):性能和优化
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表