摘要:上一篇文章指南更新文档下一篇文章指南特定类型的查询本章将详细介绍查询。查询条件和就是全部的比较操作符,分别对应和。如果查询优化器可以更高效地处理,那就选择使用它。注意,查询优化器不会对进行优化,这与其他操作符不同。
上一篇文章:MongoDB指南---6、更新文档
下一篇文章:MongoDB指南---8、特定类型的查询
本章将详细介绍查询。主要会涵盖以下几个方面:
使用find或者findOne函数和查询文档对数据库执行查询;
使用$条件查询实现范围查询、数据集包含查询、不等式查询,以及其他一些查询;
查询将会返回一个数据库游标,游标只会在你需要时才将需要的文档批量返回;
还有很多针对游标执行的元操作,包括忽略一定数量的结果,或者限定返回结果的数量,以及对结果排序。
4.1 find简介MongoDB中使用find来进行查询。查询就是返回一个集合中文档的子集,子集合的范围从0个文档到整个集合。find的第一个参数决定了要返回哪些文档,这个参数是一个文档,用于指定查询条件。
空的查询文档(例如{})会匹配集合的全部内容。要是不指定查询文档,默认就是{}。例如:
> db.c.find()
将批量返回集合c中的所有文档。
开始向查询文档中添加键/值对时,就意味着限定了查询条件。对于绝大多数类型来说,这种方式很简单明了。数值匹配数值,布尔类型匹配布尔类型,字符串匹配字符串。查询简单的类型,只要指定想要查找的值就好了,十分简单。例如,想要查找"age"值为27的所有文档,直接将这样的键/值对写进查询文档就好了:
> db.users.find({"age" : 27})
要是想匹配一个字符串,比如值为"joe"的"username"键,那么直接将键/值对写在查询文档中即可:
> db.users.find({"username" : "joe"})
可以向查询文档加入多个键/值对,将多个查询条件组合在一起,这样的查询条件会被解释成“条件1AND条件2AND ... AND条件N”。例如,要想查询所有用户名为joe且年龄为27岁的用户,可以像下面这样:
> db.users.find({"username" : "joe", "age" : 27})4.1.1 指定需要返回的键
有时并不需要将文档中所有键/值对都返回。遇到这种情况,可以通过find(或者findOne)的第二个参数来指定想要的键。这样做既会节省传输的数据量,又能节省客户端解码文档的时间和内存消耗。
例如,如果只对用户集合的"username"和"email"键感兴趣,可以使用如下查询返回这些键:
> db.users.find({}, {"username" : 1, "email" : 1}) { "_id" : ObjectId("4ba0f0dfd22aa494fd523620"), "username" : "joe", "email" : "joe@example.com" }
可以看到,默认情况下"_id"这个键总是被返回,即便是没有指定要返回这个键。
也可以用第二个参数来剔除查询结果中的某些键/值对。例如,文档中有很多键,但是我们不希望结果中含有"fatal_weakness"键:
> db.users.find({}, {"fatal_weakness" : 0})
使用这种方式,也可以把"_id"键剔除掉:
> db.users.find({}, {"username" : 1, "_id" : 0}) { "username" : "joe", }4.1.2 限制
查询的使用上有些限制。传递给数据库的查询文档的值必须是常量。(在你自己的代码里可以是正常的变量。)也就是不能引用文档中其他键的值。例如,要想保持库存,有"in_stock"(剩余库存)和"num_sold"(已出售)两个键,想通过下列查询来比较两者的值是行不通的:
> db.stock.find({"in_stock" : "this.num_sold"}) // 这样是行不通的
的确有办法实现类似的操作(详见4.4节),但通常需要略微修改一下文档结构,就能通过普通查询来完成这样的操作了,这种方式性能更好。在这个例子中,可以在文档中使用"initial_stock"(初始库存)和"in_stock"两个键。这样,每当有人购买物品,就将"in_stock"减去1。这样,只需要用一个简单的查询就能知道哪种商品已脱销:
> db.stock.find({"in_stock" : 0})4.2 查询条件
查询不仅能像前面说的那样精确匹配,还能匹配更加复杂的条件,比如范围、OR子句和取反。
4.2.1 查询条件"$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"}})
"$ne"能用于所有类型的数据。
4.2.2 OR查询MongoDB中有两种方式进行OR查询:"$in"可以用来查询一个键的多个值;"$or"更通用一些,可以在多个键中查询任意的给定值。
如果一个键需要与多个值进行匹配的话,就要用"$in"操作符,再加一个条件数组。例如,抽奖活动的中奖号码是725、542和390。要找出全部的中奖文档的话,可以构建如下查询:
> db.raffle.find({"ticket_no" : {"$in" : [725, 542, 390]}})
"$in"非常灵活,可以指定不同类型的条件和值。例如,在逐步将用户的ID号迁移成用户名的过程中,查询时需要同时匹配ID和用户名:
> db.users.find({"user_id" : {"$in" : [12345, "joe"]})
这会匹配"user_id"等于12345的文档,也会匹配"user_id"等于"joe"的文档。
要是"$in"对应的数组只有一个值,那么和直接匹配这个值效果一样。例如,{ticket_no : {$in:[725]}}和{ticket_no : 725}的效果一样。
与"$in"相对的是"$nin","$nin"将返回与数组中所有条件都不匹配的文档。要是想返回所有没有中奖的人,就可以用如下方法进行查询:
> db.raffle.find({"ticket_no" : {"$nin" : [725, 542, 390]}})
该查询会返回所有没有中奖的人。
"$in"能对单个键做OR查询,但要是想找到"ticket_no"为725或者"winner"为true的文档该怎么办呢?对于这种情况,应该使用"$or"。"$or"接受一个包含所有可能条件的数组作为参数。上面中奖的例子如果用"$or"改写将是下面这个样子:
> db.raffle.find({"$or" : [{"ticket_no" : 725}, {"winner" : true}]})
"$or"可以包含其他条件。例如,如果希望匹配到中奖的"ticket_no",或者"winner"键的值为true的文档,就可以这么做:
> db.raffle.find({"$or" : [{"ticket_no" : {"$in" : [725, 542, 390]}}, {"winner" : true}]})
使用普通的AND型查询时,总是希望尽可能用最少的条件来限定结果的范围。OR型查询正相反:第一个条件应该尽可能匹配更多的文档,这样才是最为高效的。
"$or"在任何情况下都会正常工作。如果查询优化器可以更高效地处理"$in",那就选择使用它。
"$not"是元条件句,即可以用在任何其他条件之上。就拿取模运算符"$mod"来说。"$mod"会将查询的值除以第一个给定值,若余数等于第二个给定值则匹配成功:
> db.users.find({"id_num" : {"$mod" : [5, 1]}})
上面的查询会返回"id_num"值为1、6、11、16等的用户。但要是想返回"id_num"为2、3、4、5、7、8、9、10、12等的用户,就要用"$not"了:
> db.users.find({"id_num" : {"$not" : {"$mod" : [5, 1]}}})
"$not"与正则表达式联合使用时极为有用,用来查找那些与特定模式不匹配的文档(4.3.2节会详细讲述正则表达式的使用)。
4.2.4 条件语义如果比较一下上一章的更新修改器和前面的查询文档,会发现以$开头的键位于在不同的位置。在查询中,"$lt"在内层文档,而更新中"$inc"则是外层文档的键。基本可以肯定:条件语句是内层文档的键,而修改器则是外层文档的键。
可以对一个键应用多个条件。例如,要查找年龄为20~30的所有用户,可以在"age"键上使用"$gt"和"$lt":
> db.users.find({"age" : {"$lt" : 30, "$gt" : 20}})
一个键可以有任意多个条件,但是一个键不能对应多个更新修改器。例如,修改器文档不能同时含有{"$inc" : {"age" : 1}, "$set" : {age : 40}},因为修改了"age"两次。但是对于查询条件句就没有这种限定。
有一些“元操作符”(meta-operator)也位于外层文档中,比如"$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指南---6、更新文档
下一篇文章:MongoDB指南---8、特定类型的查询
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/19561.html
摘要:上一篇文章指南更新文档下一篇文章指南特定类型的查询本章将详细介绍查询。查询条件和就是全部的比较操作符,分别对应和。如果查询优化器可以更高效地处理,那就选择使用它。注意,查询优化器不会对进行优化,这与其他操作符不同。 上一篇文章:MongoDB指南---6、更新文档下一篇文章:MongoDB指南---8、特定类型的查询 本章将详细介绍查询。主要会涵盖以下几个方面: 使用find或者f...
摘要:但有时我们希望返回与查询条件相匹配的任意一个数组元素。首先,可以使用要求同时使用查询条件中的两个语句与一个数组元素进行比较。 上一篇文章:MongoDB指南---7、find简介与查询条件下一篇文章:MongoDB指南---9、游标与数据库命令 如第2章所述,MongoDB的文档可以使用多种类型的数据。其中有一些在查询时会有特别的表现。 4.3.1 null null类型的行为有点奇...
摘要:但有时我们希望返回与查询条件相匹配的任意一个数组元素。首先,可以使用要求同时使用查询条件中的两个语句与一个数组元素进行比较。 上一篇文章:MongoDB指南---7、find简介与查询条件下一篇文章:MongoDB指南---9、游标与数据库命令 如第2章所述,MongoDB的文档可以使用多种类型的数据。其中有一些在查询时会有特别的表现。 4.3.1 null null类型的行为有点奇...
摘要:可以通过来强制使用某个特定的索引,再次执行这个查询,但是这次使用,作为索引。 上一篇文章:MongoDB指南---9、游标与数据库命令下一篇文章:MongoDB指南---11、使用复合索引、$操作符如何使用索引、索引对象和数组、索引基数 本章介绍MongoDB的索引,索引可以用来优化查询,而且在某些特定类型的查询中,索引是必不可少的。 什么是索引?为什么要用索引? 如何选择需要建立...
摘要:可以通过来强制使用某个特定的索引,再次执行这个查询,但是这次使用,作为索引。 上一篇文章:MongoDB指南---9、游标与数据库命令下一篇文章:MongoDB指南---11、使用复合索引、$操作符如何使用索引、索引对象和数组、索引基数 本章介绍MongoDB的索引,索引可以用来优化查询,而且在某些特定类型的查询中,索引是必不可少的。 什么是索引?为什么要用索引? 如何选择需要建立...
阅读 1695·2021-11-24 09:39
阅读 2468·2021-11-18 10:07
阅读 3656·2021-08-31 09:40
阅读 3316·2019-08-30 15:44
阅读 2627·2019-08-30 12:50
阅读 3648·2019-08-26 17:04
阅读 1429·2019-08-26 13:49
阅读 1261·2019-08-23 18:05