3.1 查询操作符
操作符就是对数据进行操作的符号,其表达了要对数据执行的操作。数据库系统的每一条查询指令都有一个操作符,表示该指令应该执行什么性质的操作。
- 条件操作符
最常用也是最简单的操作符<、<=、>、>=如下面的代码所示:
//field 大于 value
db.collection.find({"field":{$gt:value}});
//field 小于 value
db.collection.find({"field":{$lt:value}});
//field 大于等于 value
db.collection.find({"field":{$gte:value}});
//field 小于等于 value
db.collection.find({"field":{$lte:value}});
如果要同时满足多个条件,可以如下面的代码所示:
//value1 < field < value2
db.collection.find({"field":{$gt:value1,$lt:value2}});
- $all匹配所有
此操作符跟SQL语法的in类似,不同的是in只需要匹配括号内的某一个值,而$all必须满足括号内的所有值,如下面的代码所示:
db.users.find({age:{$all:[6, 8]}});
上例可以查询出以下文档:
{name: 'David', age: 26, age: [ 6, 8, 9 ] }
但查询不出以下这条文档:
{name: 'David', age: 26, age: [ 6, 7, 9 ] }
- $exists判断字段是否存在
此操作符用于判断某个字段是否存在,例如查询所有存在age字段的记录,如下面的代码所示:
db.users.find({age: {$exists: true}});
查询所有不存在name字段的记录,如下面的代码所示:
db.users.find({name: {$exists: false}});
接下来举一个实际的例子,c1表的数据如下面的代码所示:
> db.c1.find();
{ "_id" : ObjectId("4fb4a773afa87dc1bed9432d"), "age" : 20, "length" : 30 }
{ "_id" : ObjectId("4fb4a7e1afa87dc1bed9432e"), "age_1" : 20, "length_1" : 30 }
查询存在字段age的数据,如下面的代码所示:
> db.c1.find({age:{$exists:true}});
{ "_id" : ObjectId("4fb4a773afa87dc1bed9432d"), "age" : 20, "length" : 30 }
通过实验结果可以看出只显示了age字段的数据,age_1的数据并没有显示出来。
- null值处理
此操作符用于处理null值,null值的处理稍微复杂,如下面的代码所示:
> db.c2.find()
{ "_id" : ObjectId("4fc34bb81d8a39f01cc17ef4"), "name" : "Lily", "age" : null }
{ "_id" : ObjectId("4fc34be01d8a39f01cc17ef5"), "name" : "Jacky", "age" : 23 }
{ "_id" : ObjectId("4fc34c1e1d8a39f01cc17ef6"), "name" : "Tom", "addr" : 23 }
其中,“Lily”的age字段为空,“Tom”没有age字段,想找到age为空的行如下面的代码所示:
> db.c2.find({age:null})
{ "_id" : ObjectId("4fc34bb81d8a39f01cc17ef4"), "name" : "Lily", "age" : null }
{ "_id" : ObjectId("4fc34c1e1d8a39f01cc17ef6"), "name" : "Tom", "addr" : 23 }
奇怪的是,我们以为只能找到“Lily”,但“Tom”也被找出来了,所以“null”不仅能找到它自身,也能找到不存在age字段的记录。那么怎么样才能只找到“Lily”呢?用exists来限制一下即可,如下面的代码所示:
> db.c2.find({age:{"$in":[null], "$exists":true}})
{ "_id" : ObjectId("4fc34bb81d8a39f01cc17ef4"), "name" : "Lily", "age" : null }
跟期望的结果一样,只有“Lily”被找出来了。
- $mod取模运算
此操作符用于取模运算。例如查询age取模10等于1的数据,如下面的代码所示:
db.student.find( { age: { $mod : [ 10 , 1 ] } } )
接下来举一个实际的例子,c1表的数据如下面的代码所示:
> db.c1.find()
{ "_id" : ObjectId("4fb4af85afa87dc1bed94330"), "age" : 7, "length_1" : 30 }
{ "_id" : ObjectId("4fb4af89afa87dc1bed94331"), "age" : 8, "length_1" : 30 }
{ "_id" : ObjectId("4fb4af8cafa87dc1bed94332"), "age" : 6, "length_1" : 30 }
查询age取模6等于1的数据,如下面的代码所示:
> db.c1.find({age: {$mod : [ 6 , 1 ] } })
{ "_id" : ObjectId("4fb4af85afa87dc1bed94330"), "age" : 7, "length_1" : 30 }
可以看出,只显示age取模6等于1的数据,其他不符合规则的数据并没有显示出来。
- $ne不等于
此操作符用于布尔不等于的运算。例如查询x的值不等于3的数据,如下面的代码所示:
db.things.find( { x : { $ne : 3 } } );
接下来举一个实际的例子,c1表的数据如下面的代码所示:
> db.c1.find()
{ "_id" : ObjectId("4fb4af85afa87dc1bed94330"), "age" : 7, "length_1" : 30 }
{ "_id" : ObjectId("4fb4af89afa87dc1bed94331"), "age" : 8, "length_1" : 30 }
{ "_id" : ObjectId("4fb4af8cafa87dc1bed94332"), "age" : 6, "length_1" : 30 }
查询age的值不等于7的数据,如下面的代码所示:
> db.c1.find( { age : { $ne : 7 } } )
{ "_id" : ObjectId("4fb4af89afa87dc1bed94331"), "age" : 8, "length_1" : 30 }
{ "_id" : ObjectId("4fb4af8cafa87dc1bed94332"), "age" : 6, "length_1" : 30 }
可以看出,只显示age不等于7的数据,age等于7的数据没有显示出来。
- $in包含
此操作符与SQL标准语法的用途一样,即要查询的数据在一个特定的取值范围内。
例如,查询x的值在2、4、6范围内的数据,如下面的代码所示:
db.things.find({x:{$in: [2,4,6]}});
接下来举一个实际的例子,c1表的数据如下面的代码所示:
> db.c1.find()
{ "_id" : ObjectId("4fb4af85afa87dc1bed94330"), "age" : 7, "length_1" : 30 }
{ "_id" : ObjectId("4fb4af89afa87dc1bed94331"), "age" : 8, "length_1" : 30 }
{ "_id" : ObjectId("4fb4af8cafa87dc1bed94332"), "age" : 6, "length_1" : 30 }
查询age的值在7、8范围内的数据,如下面的代码所示:
> db.c1.find({age:{$in: [7,8]}})
{ "_id" : ObjectId("4fb4af85afa87dc1bed94330"), "age" : 7, "length_1" : 30 }
{ "_id" : ObjectId("4fb4af89afa87dc1bed94331"), "age" : 8, "length_1" : 30 }
可以看出只显示age等于7或8的数据,其他不符合规则的数据并没有显示出来。
- $nin不包含
此操作符与SQL标准语法的用途是一样的,即要查询的数据在一系列枚举值的范围外。
查询x的值在2、4、6范围外的数据,如下面的代码所示:
db.things.find({x:{$nin: [2,4,6]}});
接下来举一个实际的例子,c1表的数据如下面的代码所示:
> db.c1.find()
{ "_id" : ObjectId("4fb4af85afa87dc1bed94330"), "age" : 7, "length_1" : 30 }
{ "_id" : ObjectId("4fb4af89afa87dc1bed94331"), "age" : 8, "length_1" : 30 }
{ "_id" : ObjectId("4fb4af8cafa87dc1bed94332"), "age" : 6, "length_1" : 30 }
查询age的值在7、8范围外的数据,如下面的代码所示:
> db.c1.find({age:{$nin: [7,8]}})
{ "_id" : ObjectId("4fb4af8cafa87dc1bed94332"), "age" : 6, "length_1" : 30 }
通过结果可以看出只显示age不等于7或8的数据,其他不符合规则的数据并没有显示出来。
- $size匹配数组元素个数
此操作符用于统计数组中的元素个数。例如,对于记录:
{name: 'David', age: 26, favorite_number: [ 6, 7, 9 ] }
它匹配以下查询:
db.users.find({favorite_number: {$size: 3}})
但不匹配以下查询:
db.users.find({favorite_number: {$size: 2}})
10. count查询记录条数
此操作符用于统计记录的条数。如下面的代码所示:
db.users.find().count();
以下返回的不是5,而是user表中所有记录的数量,如下面的代码所示:
db.users.find().skip(10).limit(5).count();
如果要返回限制之后的记录数量,要使用count(true)或者count(非0) ,如下面的代码所示:
db.users.find().skip(10).limit(5).count(true);
接下来举一个实际的例子,c1表的数据如下面的代码所示:
> db.c1.find()
{ "_id" : ObjectId("4fb5faaf6d0f9d8ea3fc91a8"), "name" : "Tony", "age" : 20 }
{ "_id" : ObjectId("4fb5fab96d0f9d8ea3fc91a9"), "name" : "Joe", "age" : 10 }
查询c1表的数据量,如下面的代码所示:
> db.c1.count()
2
通过结果可以看出,表中共有2条数据。
- skip限制返回记录的起点
此操作符用于过滤结果集中的某些行。例如,从第3条记录开始,返回5条记录 ,如下面的代码所示:
db.users.find().skip(3).limit(5);
接下来举一个实际的例子,c1表的数据如下面的代码所示:
> db.c1.find()
{ "_id" : ObjectId("4fb5faaf6d0f9d8ea3fc91a8"), "name" : "Tony", "age" : 20 }
{ "_id" : ObjectId("4fb5fab96d0f9d8ea3fc91a9"), "name" : "Joe", "age" : 10 }
查询c1表的第2条数据,如下面的代码所示:
> db.c1.find().skip(1).limit(1)
{ "_id" : ObjectId("4fb5fab96d0f9d8ea3fc91a9"), "name" : "Joe", "age" : 10 }
通过结果可以看出,表中第2条数据被显示了出来。
- sort排序
此操作符用于将结果集排序。例如,以年龄升序(asc)排列,如下面的代码所示:
db.users.find().sort({age: 1});
以年龄降序(desc)排列,如下面的代码所示:
db.users.find().sort({age: -1});
接下来举一个实际的例子,c1表的数据如下面的代码所示:
> db.c1.find()
{ "_id" : ObjectId("4fb5faaf6d0f9d8ea3fc91a8"), "name" : "Tony", "age" : 20 }
{ "_id" : ObjectId("4fb5fab96d0f9d8ea3fc91a9"), "name" : "Joe", "age" : 10 }
查询c1表按age升序排列,如下面的代码所示:
> db.c1.find().sort({age: 1})
{ "_id" : ObjectId("4fb5fab96d0f9d8ea3fc91a9"), "name" : "Joe", "age" : 10 }
{ "_id" : ObjectId("4fb5faaf6d0f9d8ea3fc91a8"), "name" : "Tony", "age" : 20 }
通过结果可看到第1条是age=10的,而后按升序排列结果集。
查询c1表按age降序排列,如下面的代码所示:
> db.c1.find().sort({age: -1})
{ "_id" : ObjectId("4fb5faaf6d0f9d8ea3fc91a8"), "name" : "Tony", "age" : 20 }
{ "_id" : ObjectId("4fb5fab96d0f9d8ea3fc91a9"), "name" : "Joe", "age" : 10 }
通过结果可看到第1条是age=20的,而后按降序排列结果集。
- distinct去掉重复值
在表中可能会包含重复值,distinct操作符用来过滤掉多余的重复记录, 对于重复记录只保留一条。通常用它来返回不重复记录的条数,如下面的代码所示:
> db.t2.find()
{ "_id" : ObjectId("4e023565b42bc90ec25b7c07"), "name" : "Tom", "age" : 20 }
{ "_id" : ObjectId("4e023565b42bc90ec25b7c08"), "name" : "Jerry", "age" : 20 }
{ "_id" : ObjectId("4e023566b42bc90ec25b7c09"), "name" : "Rose", "age" : 18 }
>
> db.t2.distinct("name")
[ "Tom", "Jerry", "Rose" ]
>
> db.t2.distinct("age")
[ 20, 18 ]
>
name的不重复值为3个,age的不重复值为2个,调用distinct操作符后,返回一个列表,里面包含了不重复值的枚举值。
注意 这种操作在数据量较大的表里会比较耗时,请慎重使用这个功能。
- group分组统计
- by子句主要用于对where中得到的结果进行分组。也就是说,它在where子句之后执行,对经过where筛选后的结果按照某些列进行分组,之后进行相应的处理工作。
当使用聚集函数的时候,除非对整个语句的查询结果集进行聚集运算,否则都要通过指定group by子句来确定是对某类结果集进行聚集运算,如下面的传统SQL代码所示:
select a,b,sum(c) csum from coll where active=1 group by a,b
上面的语句用MongoDB也是可以实现的,如下面的代码所示:
db.coll.group(
{key: { a:true, b:true },
cond: { active:1 },
reduce: function(obj,prev) { prev.csum += obj.c; },
initial: { csum: 0 }
});
参数说明:
1)key:要分组的列。本例中为a和b。
2)cond:分组条件。可以理解为where条件内容,本例中为active=1。
3)reduce: 分组计算的方法。本例中为sum(c)。
4)initial:分组计算的初始值。本例中指csum的值从0开始计算。