一、简单查询
MongoDB中使用find来进行查询,查询就是返回一个集合中文档的子集,子集合的范围从0个文档到整个集合。Find的第一个参数决定了要返回哪些文档,其形式也是一个文档,说明要执行的查询细节。
1 2 3 4 5 |
> db.colltest.find() { "_id" : ObjectId("569c23309c09c9857f00a20b"), "name" : "eric", "age" : 21, "class" : 3 } { "_id" : ObjectId("569c233a9c09c9857f00a20c"), "name" : "andy", "age" : 21, "class" : 2 } { "_id" : ObjectId("569c234a9c09c9857f00a20d"), "name" : "jerry", "age" : 24, "class" : 3 } { "_id" : ObjectId("569c23599c09c9857f00a20e"), "name" : "jerry", "age" : 22, "class" : 2 } |
find()默认一次最多显示20行,输入it可以继续显示。
find()方法以非结构化的方式来显示所有文档,如果你需要以易读的方式来读取数据,可以使用pretty()方法,语法如下:
1 2 3 4 5 6 7 |
> db.colltest.find().pretty() { "_id" : ObjectId("569c23309c09c9857f00a20b"), "name" : "eric", "age" : 21, "class" : 3 } |
除了find()方法之外,还有一个findOne()方法,它只返回一个文档。
1 2 3 4 5 6 7 |
> db.colltest.findOne() { "_id" : ObjectId("569c23309c09c9857f00a20b"), "name" : "eric", "age" : 21, "class" : 3 } |
当我们开始向查询文档中添加键/值对时,就意味着限定了查找的条件,对于绝大多数类型来说,这种方式很简单明了。整数匹配整数,布尔类型匹配布尔类型,字符串匹配字符串。查询简单的类型,只要指定想要查找的值就好了。例如,想要查找所有“title”的值为mongodb的文档,直接将这样的键/值对写进查询文档就好了:
1 2 3 |
> db.colltest.find({'name':'jerry'}) { "_id" : ObjectId("569c234a9c09c9857f00a20d"), "name" : "jerry", "age" : 24, "class" : 3 } { "_id" : ObjectId("569c23599c09c9857f00a20e"), "name" : "jerry", "age" : 22, "class" : 2 } |
可以通过向查询文档假如多个键/值对的方式来将多个查询条件组合在一起,会解释成“条件1 AND 条件2 AND….AND 条件N”。例如,要想查询所有名字为“jerry”且年龄为22岁的同学。
1 2 |
> db.colltest.find({'name':'jerry','age':22}) { "_id" : ObjectId("569c23599c09c9857f00a20e"), "name" : "jerry", "age" : 22, "class" : 2 } |
1)指定返回的键(列)
有时并不需要将文档中所有键/值对都返回,可以指定返回的键,类似于SQL中返回指定的字段一样,语法如下:
1 2 3 4 5 |
> db.colltest.find({},{'name':1,'age':1}) { "_id" : ObjectId("569c23309c09c9857f00a20b"), "name" : "eric", "age" : 21 } { "_id" : ObjectId("569c233a9c09c9857f00a20c"), "name" : "andy", "age" : 21 } { "_id" : ObjectId("569c234a9c09c9857f00a20d"), "name" : "jerry", "age" : 24 } { "_id" : ObjectId("569c23599c09c9857f00a20e"), "name" : "jerry", "age" : 22 } |
其中 ‘name’: 1 表示显示指定的 name 键,如果为 0 表示显示除 name 键之外的所有键,也就是取反操作。
例如,文档中有很多键,但是不需要结果中含有“age”键:
1 2 3 4 5 |
> db.colltest.find({},{'age':0}) { "_id" : ObjectId("569c23309c09c9857f00a20b"), "name" : "eric", "class" : 3 } { "_id" : ObjectId("569c233a9c09c9857f00a20c"), "name" : "andy", "class" : 2 } { "_id" : ObjectId("569c234a9c09c9857f00a20d"), "name" : "jerry", "class" : 3 } { "_id" : ObjectId("569c23599c09c9857f00a20e"), "name" : "jerry", "class" : 2 } |
另外可以看到,“_id”这个键总是被返回,即便是没有指定也一样。
可以使用去反操作来过滤不显示“_id”。
1 2 3 4 5 |
> db.colltest.find({},{'_id':0}) { "name" : "eric", "age" : 21, "class" : 3 } { "name" : "andy", "age" : 21, "class" : 2 } { "name" : "jerry", "age" : 24, "class" : 3 } { "name" : "jerry", "age" : 22, "class" : 2 } |
2)查询条件
查询不仅能像前面说的那样精确匹配,还能匹配更加复杂的条件,比如范围、OR子句和取反等。
① 比较操作
1 2 3 4 5 6 7 |
$lt – 挑选指定字段值小于指定值的文档,语法{field:{$lt:value}}; $lte – 挑选指定字段值小于等于指定值的文档,语法{field:{$lte:value}}; $gt – 挑选指定字段值大于指定值的文档,语法{field:{$gt:value}}; $gte – 挑选指定字段值大于等于指定值的文档,语法{field:{$gte:value}}; $ne – 挑选指定字段值不等于指定值的文档,语法{field:{$ne:value}}; $in – 挑选指定字段值位于指定数组中的文档,语法{field:{$in:[value1,value2]}}; $nin – 挑选指定字段值没有位于数组中或不存在的文档,语法{field:{$nin:[value1,value2]}}; |
可以将其组合起来以便查找一个范围的值,例如,查询年龄在22~24(含)的同学,就可以像下面这样:
1 2 3 |
> db.colltest.find({'age':{"$gte":22,"$lte":24}}) { "_id" : ObjectId("569c234a9c09c9857f00a20d"), "name" : "jerry", "age" : 24, "class" : 3 } { "_id" : ObjectId("569c23599c09c9857f00a20e"), "name" : "jerry", "age" : 22, "class" : 2 } |
这样的范围查询对日期尤为有用,例如,要查找在2016年1月1日前注册的人,可以像下面这样:
1 2 3 |
> start = new Date("01/01/2016") ISODate("2015-12-31T16:00:00Z") > db.colltest.find({'regi':{"$lt":start}}) |
用“$in”加一个条件数组。例如,找出年龄在22、23、24、25中的同学。
1 2 3 |
> db.colltest.find({'age':{"$in":[22,23,24,25]}}) { "_id" : ObjectId("569c234a9c09c9857f00a20d"), "name" : "jerry", "age" : 24, "class" : 3 } { "_id" : ObjectId("569c23599c09c9857f00a20e"), "name" : "jerry", "age" : 22, "class" : 2 } |
与“$in”相对的是“$nin”,将返回与数据中所有条件都不匹配的文档。
1 2 3 |
> db.colltest.find({'age':{"$nin":[22,23,24,25]}}) { "_id" : ObjectId("569c23309c09c9857f00a20b"), "name" : "eric", "age" : 21, "class" : 3 } { "_id" : ObjectId("569c233a9c09c9857f00a20c"), "name" : "andy", "age" : 21, "class" : 2 } |
② 逻辑查询
逻辑运算一般用于连接多个选择条件,Mongodb支持的逻辑运算有如下几种:
$or – 或运算,语法{$operator:[{},{}]}
1 2 3 |
> db.colltest.find({$or:[{'name':'eric'},{'age':22}]}) { "_id" : ObjectId("569cff66d7b12904ce15646d"), "name" : "eric", "age" : 21, "class" : 3 } { "_id" : ObjectId("569cff87d7b12904ce156470"), "name" : "jerry", "age" : 22, "class" : 2 } |
$and – 与运算,语法{$operator:[{},{}]}
1 2 |
> db.colltest.find({$and:[{'name':'jerry'},{'age':22}]}) { "_id" : ObjectId("569cff87d7b12904ce156470"), "name" : "jerry", "age" : 22, "class" : 2 } |
$nor – 反运算,语法{$operator:[{},{}]}
1 2 3 |
> db.colltest.find({$nor:[{name:'jerry'}]}) { "_id" : ObjectId("569cff66d7b12904ce15646d"), "name" : "eric", "age" : 21, "class" : 3 } { "_id" : ObjectId("569cff6ed7b12904ce15646e"), "name" : "andy", "age" : 21, "class" : 2 } |
$not – 非运算,语法{$operator:[{},{}]}
1 2 3 |
> db.colltest.find({name:{$not:/^j.*/}}) { "_id" : ObjectId("569cff66d7b12904ce15646d"), "name" : "eric", "age" : 21, "class" : 3 } { "_id" : ObjectId("569cff6ed7b12904ce15646e"), "name" : "andy", "age" : 21, "class" : 2 } |
③ 元素查询
如果要根据文档中是否存在某字段等条件来挑选文档,则需要用到元素运算。
$exists – 根据指定字段的存在性挑选文档,语法{field:$exists:<boolean>},指定<boolean>的值为“true”则返回存在指定字段的文档,为“false”则返回不存在指定字段的文档。
1 |
> db.colltest.find({'name':{$exists:true}}) |
$mod – 将指定字段的值以第一个给定的值进行取模运算,并返回其余数为第二个给定值的文档;语法{field:{$mod:[divisor,remainder]}}
1 2 3 |
> db.colltest.find({'age':{$mod:[5,1]}}) { "_id" : ObjectId("569cff66d7b12904ce15646d"), "name" : "eric", "age" : 21, "class" : 3 } { "_id" : ObjectId("569cff6ed7b12904ce15646e"), "name" : "andy", "age" : 21, "class" : 2 } |
$type – 返回指定字段的值类型为指定类型的文档,语法{field:$type:<BSON type>}
④ 正则表达式
1 2 3 |
> db.colltest.find({name:/^j.*/}) { "_id" : ObjectId("569cff7ed7b12904ce15646f"), "name" : "jerry", "age" : 24, "class" : 3 } { "_id" : ObjectId("569cff87d7b12904ce156470"), "name" : "jerry", "age" : 22, "class" : 2 } |
3)特定类型查询
null
null可以匹配自身,所以要是有一个包含null的集合,就可以使用如下方法查询出来:
1 |
> db.colltest.find({'age':null}) |
数组
查询数组中的元素也是非常容易的,数组绝大多数情况下可以这样理解:每一个元素都是整个键的值。例如,如果数组是一个水果清单,比如下面这样:
1 |
> db.food.insert({'fruit':['apple','banana','peach']}) |
下面的查询
1 2 |
> db.food.find({'fruit':"banana"}) { "_id" : ObjectId("569c2f259c09c9857f00a20f"), "fruit" : [ "apple", "banana", "peach" ] } |
$all
如果需要通过多个元素来匹配数组,就要用“$all”了。这样就会匹配一组元素。例如,假设创建包含3个元素的如下集合:
1 2 3 |
> db.food.insert({'fruit':['apple','banana','peach']}) > db.food.insert({'fruit':['apple','orange','kumquat']}) > db.food.insert({'fruit':['cherry','banana','apple']}) |
要找到既有“apple”又有“banana”的文档,就得用“$all”来查询:
1 2 3 |
> db.food.find({'fruit':{$all:['banana','apple']}}) { "_id" : ObjectId("569c2f259c09c9857f00a20f"), "fruit" : [ "apple", "banana", "peach" ] } { "_id" : ObjectId("569c2fc89c09c9857f00a211"), "fruit" : [ "cherry", "banana", "apple" ] } |
$size
“$size“对于查询数组来说也是意义非凡,顾名思义,可以用其查询指定长度的数组,见下面的例子:
1 2 3 4 |
> db.food.find({'fruit':{"$size":3}}) { "_id" : ObjectId("569c2f259c09c9857f00a20f"), "fruit" : [ "apple", "banana", "peach" ] } { "_id" : ObjectId("569c2fb29c09c9857f00a210"), "fruit" : [ "apple", "orange", "kumquat" ] } { "_id" : ObjectId("569c2fc89c09c9857f00a211"), "fruit" : [ "cherry", "banana", "apple" ] } |
4)find常用方法
limit()
如果你需要在MongoDB中读取指定数量的数据记录,可以使用MongoDB的Limit方法,limit()方法接受一个数字参数,该参数指定从MongoDB中读取的记录条数。
1 2 |
> db.colltest.find().limit(1) { "_id" : ObjectId("569c23309c09c9857f00a20b"), "name" : "eric", "age" : 21, "class" : 3 } |
skip()
我们除了可以使用limit()方法来读取指定数量的数据外,还可以使用skip()方法来限制返回文档的起点,skip方法同样接受一个数字参数作为跳过的记录条数。
1 2 |
> db.colltest.find().skip(3) { "_id" : ObjectId("569c23599c09c9857f00a20e"), "name" : "jerry", "age" : 22, "class" : 2 } |
sort()
在MongoDB中使用使用sort()方法对数据进行排序,sort()方法可以通过参数指定排序的字段,并使用1和-1来指定排序的方式,其中1为升序排列,而-1是用于降序排列。
1 2 3 4 5 |
> db.colltest.find().sort({'age':-1}) { "_id" : ObjectId("569c234a9c09c9857f00a20d"), "name" : "jerry", "age" : 24, "class" : 3 } { "_id" : ObjectId("569c23599c09c9857f00a20e"), "name" : "jerry", "age" : 22, "class" : 2 } { "_id" : ObjectId("569c23309c09c9857f00a20b"), "name" : "eric", "age" : 21, "class" : 3 } { "_id" : ObjectId("569c233a9c09c9857f00a20c"), "name" : "andy", "age" : 21, "class" : 2 } |
count()
使用count()方法可以统计文档的个数。
1 2 |
> db.colltest.find().count() 4 |
二、查询为 null 或不存在的字段
MongoDB中的不同查询运算符对 null 的处理方式不同。
下面提供 mongo shell 中使用 db.collection.find() 方法查询空值的操作示例。
1 |
db.colltest.find( { item: null } ) |
{item:null}
查询表示匹配 item 字段包含值是 null 的或不包含 item 字段的文档。
1 |
db.inventory.find( { item : { $type: 10 } } ) |
{{item:{$type:10}}
查询表示只匹配 item 字段值为 null 的文档;即 item 字段的值为 BSON type Null(类型编号10)。
该查询仅返回 item 字段值为 null 的文档。
1 |
db.inventory.find( { item : { $exists: false } } ) |
{item:{$exists:false}}
查询表示仅匹配不包含 item 字段的文档。
三、游标
数据库使用游标来返回find的执行结果,要想在shell中创建一个游标,首先要对集合填充一些文档,然后对其执行查询,并将结果分配给一个局部变量,用var声明的变量就是局部变量。在mongo命令行里,当你使用var关键字把find()方法返回的游标赋值给一个变量时,它将不会自动迭代。这时候就需要手动迭代游标,在命令行里,你可以调用游标变量迭代最多20次。
1 2 3 4 |
> var mycursor = db.colltest.find({'name':'jerry'}) > mycursor { "_id" : ObjectId("569cff7ed7b12904ce15646f"), "name" : "jerry", "age" : 24, "class" : 3 } { "_id" : ObjectId("569cff87d7b12904ce156470"), "name" : "jerry", "age" : 22, "class" : 2 } |
要迭代结果,可以使用游标的next()方法来访问文档,如下例所示:
1 2 3 4 5 6 7 8 |
> var mycursor = db.colltest.find({'name':'jerry'}) > mycursor.next() { "_id" : ObjectId("569cff7ed7b12904ce15646f"), "name" : "jerry", "age" : 24, "class" : 3 } |
游标使用count()方法统计游标文档个数。
1 2 3 |
> mycursor.count() 2 |
游标使用hasNext()方法判断游标是否有值。
1 2 |
> mycursor.hasNext() true |
作为一种替代的打印操作,考虑使用printjson()助手方法来替代print(tojson()):
1 |
> while (mycursor.hasNext()) {printjson(mycursor.next());} |
你可以使用游标方法forEach()来迭代游标并且访问文档,如下例所示:
1 2 |
> var mycursor = db.colltest.find({'name':'jerry'}) > mycursor.forEach(printjson) |
PS:游标的方法使用还有很多很多,具体可以查看帮助。
四、迭代器索引
在 mongo`命令行里,你可以使用 :method:`~cursor.toArray()
方法来迭代游标,并且以数组的形式来返回文档,如下例所示:
1 2 3 4 5 6 7 8 9 |
> var mycursor = db.colltest.find({'name':'jerry'}) > var doc=mycursor.toArray() > doc[1] { "_id" : ObjectId("569cff87d7b12904ce156470"), "name" : "jerry", "age" : 22, "class" : 2 } |
五、存储过程
MongoDB同样支持存储过程,关于存储过程你需要知道的第一件事就是它是用javascript来写的。也许这会让你很奇怪,为什么它用javascript来写,但实际上它会让你非常满意。MongoDB存储过程时存储在db.system.js表中的。
<SQL到MongoDB的映射图>
https://docs.mongodb.com/manual/reference/sql-comparison/