热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

MongoDB数据库查询详解

1.find方法介绍在不传入参数的情况下,find方法缺省使用{}做参数,它匹配所有的document。我们可以传入一个查询document给find方法来限制输出,如:查找年龄为27的用户db.users.find({age:27})一个查询document里可以包括多个条件,如:查询年龄

1.find方法介绍

在不传入参数的情况下,find方法缺省使用{}做参数,它匹配所有的document。

我们可以传入一个查询document给find方法来限制输出,如:查找年龄为27的用户

>  db.users.find({ " age "  :  27 })

一个查询document里可以包括多个条件,如:查询年龄为27并且名字叫joe的用户

>  db.users.find({ " username "  :  " joe " ,  " age "  :  27 })

条件之间都是And关系。

指定查询返回的内容

有时候我们并不需要返回document里所有的key/value对,我们可以给find(或findOne)方法传入第二个参数来指定返回哪些key的值。

比如:我们只想要用户的名字和Email

>  db.users.find({}, { " username "  :  1 ,  " email "  :  1 })
{
        " _id "  : ObjectId( " 4ba0f0dfd22aa494fd523620 " ),
        " username "  :  " joe " ,
        " email "  :  " joe@example.com "
}

"_id"键总是会被返回。

如果想指定不想返回的key,如:返回除了fatal_weakness以外的key的值

>  db.users.find({}, { " fatal_weakness "  :  0 })

用这个方法可以把缺省返回的"_id"给排除掉

>  db.users.find({}, { " username "  :  1 ,  " _id "  :  0 })
{
" username "  :  " joe " ,
}

限制

查询document里边key的值对数据库来说必须是个常量,假如collection里边有两个key,一个叫int_stock一个叫num_sold,

如果我们想查询这两个key相等的document,下边的查询是行不通的

>  db.stock.find({ " in_stock "  :  " this.num_sold " })  //  doesn't work

2.查询条件

"$lt", "$lte", "$gt", 和"$gte"分别对应<,<=,>,>=

如:查询年龄在18到30之间的用户

>  db.users.find({ " age "  : { " $gte "  :  18 ,  " $lte "  :  30 }})

“$ne" 不等于,可以用于任意类型的数据

如,查找名字不叫joe的用户

>  db.users.find({ " username "  : { " $ne "  :  " joe " }})

OR查询

mongoDB里有两种使用OR的方法,如果是一个key对应的多个值,可以用"$in",还有个”or"是一种更通用的方法。

如:我们在进行一个抽奖活动,ticket No是725,542,390的三个中奖了,我们可以这样把这三个document查出来

>  db.raffle.find({ " ticket_no "  : { " $in "  : [ 725 ,  542 ,  390 ]}})

"$in"里边指定的值可以是不同的数据类型

与"$in"相反的操作就是"$nin”,返回指定的key的值不存在于数组里边的document,

>  db.raffle.find({ " ticket_no "  : { " $nin "  : [ 725 ,  542 ,  390 ]}})

上边的查询返回没中奖的所有ticket。

如果要在多个key的查询条件之间建立Or关系就得用"$or",如,查询彩票号码为725, 542, 390  或者winner为true的document

>  db.raffle.find({ " $or "  : [{ " ticket_no "  : { " $in "  : [ 725 ,  542 ,  390 ]}},{ " winner "  :  true }]})

$not

"$not"可以应用于上边说的所有的条件操作符上,举个例子之前我们先看下求余(取模)操作符"$mod","$mod"指定一个整数数组做为key的值,

里边两个数字,第一个是对其求余的数字,第二个是余数。比如,我们要找id_num的值对5求余,余数为1的document

>  db.users.find({ " id_num "  : { " $mod "  : [ 5 ,  1 ]}})

现在我们使用$not,如果找id_num对5求余后余数不为1的document

>  db.users.find({ " id_num "  : { " $not "  : { " $mod "  : [ 5 ,  1 ]}}})

规律

回头再看下前一章的更新修饰符,就会发现同样是$打头的符号,它和本章说的查询条件符号的位置是不一样的,

在查询里,"$lt"属于内层document,而更新的时候"$inc"是外层document的key。

一个key上可以有多个查询条件,却不能有多个更新。

查询年龄为20到30的用户可以这样做

>  db.users.find({ " age "  : { " $lt "  :  30 ,  " $gt "  :  20 }})

但是却没有下边这种更新修饰符

{ " $inc "  : { " age "  :  1 },  " $set "  : {age :  40 }}

3.特殊类型查询

null

null同时匹配自身和不存在的key,

>  db.c.find()
{  " _id "  : ObjectId( " 4ba0f0dfd22aa494fd523621 " ),  " y "  :  null  }
{  " _id "  : ObjectId( " 4ba0f0dfd22aa494fd523622 " ),  " y "  :  1  }
{  " _id "  : ObjectId( " 4ba0f148d22aa494fd523623 " ),  " y "  :  2  }

如果要查找y为null的document

>  db.c.find({ " y "  :  null })
{  " _id "  : ObjectId( " 4ba0f0dfd22aa494fd523621 " ),  " y "  :  null  }

查找key为null的document时,缺少此key的所有document也会返回

>  db.c.find({ " z "  :  null })
{  " _id "  : ObjectId( " 4ba0f0dfd22aa494fd523621 " ),  " y "  :  null  }
{  " _id "  : ObjectId( " 4ba0f0dfd22aa494fd523622 " ),  " y "  :  1  }
{  " _id "  : ObjectId( " 4ba0f148d22aa494fd523623 " ),  " y "  :  2  }

如果想查找key存在并且为null的document,就要用"$exists"符号,

>  db.c.find({ " z "  : { " $in "  : [ null ],  " $exists "  :  true }})

这个办法看起来比较笨,没办法,我们没有"$eq"条件符号。

正则表达式

查找名字叫joe,但是忽略大小写的document

>  db.users.find({ " name "  :  / joe / i})

mongoDB使用Perl Compatible Regular Expression (PCRE)来匹配正则表达式,所有PCRE允许的语法都可以在mongoDB里使用。

查询数组

查询数组很简单,通常情况下,数组的每个元素的值都能看作key的值。

例如,我们有一些水果

>  db.food.insert({ " fruit "  : [ " apple " ,  " banana " ,  " peach " ]})

我们查找水果里有香蕉的ducoment

>  db.food.find({ " fruit "  :  " banana " })

用起来就好像我们有这么一个document在

{ " fruit "  :  " apple " , " fruit "  :  " banana " ,  " fruit "  :  " peach " }

当然,上边这个document是不合法的。

$all

如果要匹配数组里的多个元素,就要用“$all”。

例如,我们有这样一个collection

>  db.food.insert({ " _id "  :  1 ,  " fruit "  : [ " apple " ,  " banana " ,  " peach " ]})
>  db.food.insert({ " _id "  :  2 ,  " fruit "  : [ " apple " ,  " kumquat " ,  " orange " ]})
>  db.food.insert({ " _id "  :  3 ,  " fruit "  : [ " cherry " ,  " banana " ,  " apple " ]})

要查询既有apple又有banana的document

>  db.food.find({fruit : {$all : [ " apple " ,  " banana " ]}})
{ " _id "  :  1 ,  " fruit "  : [ " apple " ,  " banana " ,  " peach " ]}
{ " _id "  :  3 ,  " fruit "  : [ " cherry " ,  " banana " ,  " apple " ]}

$all的值里边的元素是没有顺序的,只要目标包含里边的每个元素即可,如果不使用$all,就会执行精确的匹配检查。

>  db.food.find({ " fruit "  : [ " apple " ,  " banana " ,  " peach " ]})

上边这个查询会匹配第一个document

>  db.food.find({ " fruit "  : [ " apple " ,  " banana " ]})

这个查询就不会匹配第一个document

>  db.food.find({ " fruit "  : [ " banana " ,  " apple " ,  " peach " ]})

同样,这个查询也不会匹配第一个document

如果要匹配数组里指定的元素,就要使用key.index这种语法

>  db.food.find({ " fruit.2 "  :  " peach " })

index 是从0开始索引的

$size

按照数组中元素的个数查询

>  db.food.find({ " fruit "  : { " $size "  :  3 }})

$size 不能和比较条件符号(如$gt)联合使用

$slice操作符

上边曾经提到过,使用find方法的第二个参数,指定哪些键值会被返回,$slice操作符可以返回数组元素的一个子集。

例如,查找博客和它的前10条评论

>  db.blog.posts.findOne(criteria, { " comments "  : { " $slice "  :  10 }})

或者,如果想要后10条评论的话

>  db.blog.posts.findOne(criteria, { " comments "  : { " $slice "  :  - 10 }})

也可以返回中间的一段结果

>  db.blog.posts.findOne(criteria, { " comments "  : { " $slice "  : [ 23 ,  10 ]}})

上边的查询跳过前23个元素,返回第24个到第34个元素。

查询嵌入的document

查询嵌入的整个document和普通的查询没有差别,比如我们有这样一个document

{
        " name "  : {
                " first "  :  " Joe " ,
                " last "  :  " Schmoe "
        },
        " age "  :  45
}

那么我们就可以这样查询名字叫Joe Schmoe的人

>  db.people.find({ " name "  : { " first "  :  " Joe " ,  " last "  :  " Schmoe " }})

如果Joe要加一个middle name,这个查询就不行了,这种查询必须匹配整个嵌入的document,而且key是有顺序的。

我们可以用.来直接查询嵌入的key。

>  db.people.find({ " name.first "  :  " Joe " ,  " name.last "  :  " Schmoe " })

点号在查询用document里就被解释为“通向嵌入的document”,所以document的key里边不能包含点号。

$where 查询

$where子句允许你在查询里执行arbitary Javascript,使你几乎可以在查询中做任何事情。

最常见的例子就是比较document里边两个key的值。举个例子,我们有个list,我们想返回里边的key的值里有相等的document

(随便哪两个key,只要它们的value相等即可)。

>  db.foo.insert({ " apple "  :  1 ,  " banana "  :  6 ,  " peach "  :  3 })
>  db.foo.insert({ " apple "  :  8 ,  " spinach "  :  4 ,  " watermelon "  :  4 })

第二个document里,菠菜和西瓜的值是相等的,这个应该返回,这个使用$条件查询符号是做不到的。

>  db.foo.find({ " $where "  :  function  () {
...  for  ( var  current  in   this ) {
...          for  ( var  other  in   this ) {
...                  if  (current  !=  other  &&   this [current]  ==   this [other]) {
...                          return   true ;
...                 }
...         }
... }
...  return   false ;
... }});

如果函数返回true,那么这个document就会作为结果集的一部分被返回。

刚才我们定义了一个函数,给$where查询指定一个字符串是一样的效果

>  db.foo.find({ " $where "  :  " this.x + this.y == 10 " })
>  db.foo.find({ " $where "  :  " function() { return this.x + this.y == 10; } " })

这两个查询是等价的。

如非必要,尽量不要使用$where查询,$where查询比一般的查询慢很多,每个document都必须从BSON转换为一个Javascript对象,

然后执行$where表达式。而且,索引也不能使用。你可以通过组合使用$where查询和非$where查询来降低使用它的代价。

4.游标

find方法使用游标返回查询结果,游标的客户端实现使你可以对最终结果做很多的控制。在shell里创建一个游标很简单,往collection里放些document,

执行查询,将返回结果指派给一个本地变量即可。

>   for (i = 0 ; i <100 ; i ++ ) {
... db.c.insert({x : i});
... }
>   var  cursor  =  db.collection.find();

你可以使用next方法来遍历结果,使用hasNext方法来检查有没有下一个,典型的循环如下

>   while  (cursor.hasNext()) {
... obj  =  cursor.next();
...  //  do stuff
... }

cursor类同样实现了iterator接口,所以你可以使用forEach循环

>   var  cursor  =  db.people.find();
>  cursor.forEach( function (x) {
... print(x.name);
... });
adam
matt
zak

当你调用find方法的时候,shell并不会立刻去查询数据库,直到你真正请求结果的时候才发送查询,这样你可以在实际执行查询之前

追加一些其他的选项,游标的这些方法几乎都是返回游标本身,所以你可以按任意顺序链入这些方法,下边三个查询是等价的

>   var  cursor  =  db.foo.find().sort({ " x "  :  1 }).limit( 1 ).skip( 10 );
>   var  cursor  =  db.foo.find().limit( 1 ).sort({ " x "  :  1 }).skip( 10 );
>   var  cursor  =  db.foo.find().skip( 10 ).limit( 1 ).sort({ " x "  :  1 });

在这个时候查询并未执行,所有的函数都只是构建查询。现在我们调用hasNext方法,

这时候查询被送到服务器,shell就立刻取到了前100条结果或者前4MB的结果,所以接下来在调用next方法的时候就不会再发送请求

以及接受结果,当第一次返回的结果集用完的时候,shell会再次联系服务器,请求更多的结果。

Limits, Skips, 和Sorts

limit函数限制返回的结果集的上限,如,只返回3个结果

>  db.c.find().limit( 3 )

skip函数跳过前x个结果,返回剩余的

>  db.c.find().skip( 3 )

sort方法使用一组键值对做参数,key是document里的key的名字,value是1升序或者-1降序。

如,按名字升序和年龄降序排序

>  db.c.find().sort({username :  1 , age :  - 1 })

比较顺序

mongoDB有一个关于各种数据类型之间比较的等级制度。在某些情况下,你可能有一个key,它的值有多种类型,如果你想按照该

key排序,mongoDB有一个预定义好的顺序,它们从小到大分别为:

        1. Minimum value
        2. null
        3. Numbers (integers, longs, doubles)
        4. Strings
        5. Object/document
        6. Array
        7. Binary data
        8. Object ID
        9. Boolean
        10. Date
        11. Timestamp
        12. Regular expression
        13. Maximum value

获取一致性的结果

处理数据的常见方式就是从mongoDB里取出来,然后修改它,再存储进mongoDB,如下:

cursor  =  db.foo.find(); while  (cursor.hasNext()) {
        var  doc  =  cursor.next();
        doc  =  process(doc);
        db.foo.save(doc);
}

结果集数量很小的时候,这样子做是没问题的,如果结果集很大,这个做法就行不通了。

想象一下document是如何存储的,你可以像下-1一样来理解存储document的collection,每个雪花代表一个document,因为

它们和document一样,都很漂亮而且独一无二。

MongoDB权威指南(3)- Querying

-1

现在,我们执行一个find,它从头开始向右返回结果。程序获取前100个document并处理它们,然后将它们存储回数据库,如果一个

document没有足够的空间来容纳新的document,如-2,那么就需要给它重新指定存储位置。通常,这个新的document 会重新

定位到collection的尾部,如-3.

MongoDB权威指南(3)- Querying

-2

MongoDB权威指南(3)- Querying

-3

现在,我们的程序持续不断地批量获取document,当它到达collect尾部的时候,那些被重新定位的document会再次返回,如-4.

MongoDB权威指南(3)- Querying

-4

这个问题的解决办法是,对查询使用snapshot,如果添加了“$snapshot"选项,查询就会按照collection未被改变的视图运行。


推荐阅读
  • 精选10款Python框架助力并行与分布式机器学习
    随着神经网络模型的不断深化和复杂化,训练这些模型变得愈发具有挑战性,不仅需要处理大量的权重,还必须克服内存限制等问题。本文将介绍10款优秀的Python框架,帮助开发者高效地实现分布式和并行化的深度学习模型训练。 ... [详细]
  • 本文详细介绍了如何搭建一个高可用的MongoDB集群,包括环境准备、用户配置、目录创建、MongoDB安装、配置文件设置、集群组件部署等步骤。特别关注分片、读写分离及负载均衡的实现。 ... [详细]
  • 本文将详细探讨PHP中C的作用,并对比其他编程语言如Java和C的特点及其适用场景。 ... [详细]
  • MongoDB核心概念详解
    本文介绍了NoSQL数据库的概念及其应用场景,重点解析了MongoDB的基本特性、数据结构以及常用操作。MongoDB是一个高性能、高可用且易于扩展的文档数据库系统。 ... [详细]
  • 解决Parallels Desktop错误15265的方法
    本文详细介绍了在使用Parallels Desktop时遇到错误15265的多种解决方案,包括检查网络连接、关闭代理服务器和修改主机文件等步骤。 ... [详细]
  • 本文介绍了如何利用Shell脚本高效地部署MHA(MySQL High Availability)高可用集群。通过详细的脚本编写和配置示例,展示了自动化部署过程中的关键步骤和注意事项。该方法不仅简化了集群的部署流程,还提高了系统的稳定性和可用性。 ... [详细]
  • V8不仅是一款著名的八缸发动机,广泛应用于道奇Charger、宾利Continental GT和BossHoss摩托车中。自2008年以来,作为Chromium项目的一部分,V8 JavaScript引擎在性能优化和技术创新方面取得了显著进展。该引擎通过先进的编译技术和高效的垃圾回收机制,显著提升了JavaScript的执行效率,为现代Web应用提供了强大的支持。持续的优化和创新使得V8在处理复杂计算和大规模数据时表现更加出色,成为众多开发者和企业的首选。 ... [详细]
  • Oracle字符集详解:图表解析与中文乱码解决方案
    本文详细解析了 Oracle 数据库中的字符集机制,通过图表展示了不同字符集之间的转换过程,并针对中文乱码问题提供了有效的解决方案。文章深入探讨了字符集配置、数据迁移和兼容性问题,为数据库管理员和开发人员提供了实用的参考和指导。 ... [详细]
  • 提升 Kubernetes 集群管理效率的七大专业工具
    Kubernetes 在云原生环境中的应用日益广泛,然而集群管理的复杂性也随之增加。为了提高管理效率,本文推荐了七款专业工具,这些工具不仅能够简化日常操作,还能提升系统的稳定性和安全性。从自动化部署到监控和故障排查,这些工具覆盖了集群管理的各个方面,帮助管理员更好地应对挑战。 ... [详细]
  • 小王详解:内部网络中最易理解的NAT原理剖析,挑战你的认知极限
    小王详解:内部网络中最易理解的NAT原理剖析,挑战你的认知极限 ... [详细]
  • 本文探讨了如何利用 jQuery 的 JSONP 技术实现跨域调用外部 Web 服务。通过详细解析 JSONP 的工作原理及其在 jQuery 中的应用,本文提供了实用的代码示例和最佳实践,帮助开发者解决跨域请求中的常见问题。 ... [详细]
  • 尽管我们尽最大努力,任何软件开发过程中都难免会出现缺陷。为了更有效地提升对支持部门的协助与支撑,本文探讨了多种策略和最佳实践,旨在通过改进沟通、增强培训和支持流程来减少这些缺陷的影响,并提高整体服务质量和客户满意度。 ... [详细]
  • MongoDB高可用架构:深入解析Replica Set机制
    MongoDB的高可用架构主要依赖于其Replica Set机制。Replica Set通过多个mongod节点的协同工作,实现了数据的冗余存储和故障自动切换,确保了系统的高可用性和数据的一致性。本文将深入解析Replica Set的工作原理及其在实际应用中的配置和优化方法,帮助读者更好地理解和实施MongoDB的高可用架构。 ... [详细]
  • 深入解析 Redis 源码阅读方法与技巧
    在深入解析 Redis 源码的过程中,建议首先从数据结构的实现入手。这是因为在 Redis 的整体架构中,数据结构相关的代码与其他模块的耦合度较低,有助于初学者快速理解和掌握核心概念。通过阅读这些基础文件,可以为后续深入研究打下坚实的基础。 ... [详细]
  • 深入解析Tomcat:开发者的实用指南
    深入解析Tomcat:开发者的实用指南 ... [详细]
author-avatar
xiubao
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有