MongoDB基础之查询文档
1 查询操作
1.1 定义
MongoDB
查询文档使用 find()
方法
find()
方法以非结构化的方式来显示所有文档。
MongoDB 查询数据的语法格式如下:
db.collection.find(query, projection)
相关参数:
query
:可选,使用查询操作符指定查询条件projection
:可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)
若不指定projection
,则默认返回所有键,指定projection
格式如下(0
:不显示,1
:显示),有两种模式,但是两种模式不可混用
db.collection.find(query, {title: 1, by: 1})
inclusion模式 指定返回的键,不返回其他键db.collection.find(query, {title: 0, by: 0})
exclusion模式 指定不返回的键,返回其他键
比如:_id
键默认返回,需要主动指定_id:0
才会隐藏
1.2 查询操作
1.2.1 基础查询
1.2.1.1 pretty
如果需要以易读的方式来读取数据,可以使用 pretty()
方法,语法格式如下:
>db.col.find().pretty()
pretty() 方法以格式化的方式来显示所有文档。
除了 find()
方法之外,还有一个 findOne()
方法,它只返回一个文档。
1.2.1.2 求总数
count()
函数主要求总数
求集合中总数
db.col.count();
求过滤后的总数
db.col.find().count();
注意
:
在和分页联合使用时需要注意:
count()函数是假即:0或空,则查询出来是总数量
db.goods.find().count(); // 31
db.goods.find().skip(2).limit(3).count(); //31
db.goods.find().skip(2).limit(3).count(0); //31
count(1)函数是假即:1,则查询出来是实际数量
db.goods.find().skip(2).limit(3).count(1); //3
1.2.2 查询表达式
MongoDB查询表达式说明
查询表达式 | 对应SQL表达式 | 示例 | 说明描述 | 备注 |
---|---|---|---|---|
$gt |
> | {field:{$gt:value}} |
查询大于某条件的值 | |
$gte |
>= | {field:{$gte:value}} |
查询大于或等于某条件的值 | |
$lt |
< | {field:{$lt:value}} |
查询小于某条件的值 | |
$lte |
<= | {field:{$lte:value}} |
查询小于或等于某条件的值 | |
$eq |
= | {field:{$eq:value}} |
查filed列的值 等于 value 的文档 | 也可以直接用冒号: 表示等于 |
$ne |
!= | {field:{$ne:value}} |
查filed列的值 不等于 value 的文档 | |
$in |
in | db.book.find({like:{$in:[10,11,20]}}); |
查询在集合中的值 | |
$nin |
not in | db.book.find({like:{$nin:[10,11,20]}}); |
查询不在集合中 | |
$all |
无对应项,指数组所有单元匹配 | {field:{$all:[v1,v2..]}} |
取出 field列是一个数组,且至少包含 v1,v2值 | |
$slice |
无对应项,限制数组元素的个数 | $slice:[a,b] |
a是正数时,起始位置是a+1,a是负数时,起始位置a(倒数数组),b是输出个数 | |
$or |
or | {$or:[{filed1:value1,filed2:value2}]} |
查询出满足fileld1或者field2条件的文档 | |
$and |
and | {$and:[{filed1:value1,filed2:value2}]} |
查询出既有field1又有field2字段的文档 | 还可以用逗号表示and,每个键(key)以逗号 隔开,即常规 SQL 的 AND 条件 |
$not |
not | db.book.find({like:{$not:{$in:[10]}}}); |
not可以和其他连用这里是和in连用,表示不在集合中的文档 | |
$nor |
无对应项,指所有列举条件都不应成功为真 | {$nor:[条件1,条件2]} |
所有条件都不满足的文档为真返回 | |
$exists |
无对应项,某列存在则为真 | {field:{$exists:1}} |
查询出含有field字段的文档 | |
$mod |
无对应项,满足某求余则为真 | db.book.find({field:{$mod:[3,2]}}); |
查询出含有field字段除数为3余数为2的文档,即:field%3==2 |
|
$type |
无对应项,满足某类型则为真 | {field:{$exists:1}} |
查询出含有field字段的文档 | |
$where |
where | db.goods.find({$where:'this.cat_id != 3 && this.cat_id != 11'}); |
可以写成类似于SQL的语法 | 用$where 查询时, mongodb 是把bson结构的二进制数据转换为json结构的对象,然后比较对象的属性是否满足表达式.速度较慢 |
$regex |
正则表达式匹配则为真 | db.posts.find({tags:{$regex:"jav"}}) |
正则表达式效率和$where一样也不是很高 |
$type
操作符是基于BSON
类型来检索集合中匹配的数据类型,并返回结果。
MongoDB
中可以使用的类型如下表所示:
类型 | 数字 | 备注 |
---|---|---|
Double | 1 | |
String | 2 | |
Object | 3 | |
Array | 4 | |
Binary data | 5 | |
Undefined | 6 | 已废弃。 |
Object id | 7 | |
Boolean | 8 | |
Date | 9 | |
Null | 10 | |
Regular Expression | 11 | |
JavaScript | 13 | |
Symbol | 14 | |
JavaScript (with scope) | 15 | |
32-bit integer | 16 | |
Timestamp | 17 | |
64-bit integer | 18 | |
Min key | 255 | Query with -1. |
Max key | 127 |
如果想获取 合中 为 String
的数据,可以使用以下命令:
db.col.find({"title" : {$type : 2}})
或 'string'必须以字符串形式
db.col.find({"title" : {$type : 'string'}})
1.2.3 分页排序
1.2.3.1 分页limit
如果需要在MongoDB
中读取指定数量的数据记录,可以使用MongoDB
的Limit
方法,limit()
方法接受一个数字参数,该参数指定从MongoDB
中读取的记录条数。
limit()
方法基本语法如下所示:
>db.COLLECTION_NAME.find().limit(NUMBER)
注意
:如果没有指定limit()
方法中的参数则显示集合中的所有数据。
1.2.3.2 分页skip
我们除了可以使用limit()
方法来读取指定数量的数据外,还可以使用skip()
方法来跳过指定数量的数据,skip
方法同样接受一个数字参数作为跳过的记录条数。
skip() 方法脚本语法格式如下:
>db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)
以下实例只会显示第二条文档数据
>db.col.find({},{"title":1,_id:0}).limit(1).skip(1)
{ "title" : "Java 教程" }
注意
:skip()
方法默认参数为 0 。
limit(n).skip(n)
连用相当于关系型数据库中的分页操作
limit(n)
是用来规定显示的条数,而skip(n)
是用来在符合条件的记录中从第一个记录跳过的条数,这两个函数可以交换使用。
比如:find({},{age:1,_id:0}).limit(2).skip(1)
,在符合条件的文档中,要显示两条文档,显示的位置从跳过第一条记录开始
但是skip
和limit
方法只适合小数据量分页,如果是百万级效率就会非常低,因为skip
方法是一条条数据数过去的,建议使用where_limit
过滤处理
这里我们假设查询第100001条数据,这条数据的Amount值是:2399927,我们来写两条语句分别如下:
b.test.sort({"amount":1}).skip(100000).limit(10) 耗时183ms
db.test.find({amount:{$gt:2399927}}).sort({"amount":1}).limit(10) 耗时53ms
1.2.3.3 排序sort
在 MongoDB
中使用 sort()
方法对数据进行排序,sort()
方法可以通过参数指定排序的字段,并使用 1
和 -1
来指定排序的方式
1
为升序排列
-1
是用于降序排列
sort()
方法基本语法如下所示:
>db.COLLECTION_NAME.find().sort({KEY:1})
注意
:当skip(), limilt(), sort()
三个放在一起执行的时候,执行的顺序是先 sort()
, 然后是 skip()
,最后是显示的limit()
1.2.4 正则表达式
MongoDB
使用 $regex
操作符来设置匹配字符串的正则表达式。
MongoDB
使用PCRE (Perl Compatible Regular Expression)
作为正则表达式语言
我们使用正则表达式不需要做任何配置。
准备文档,该文档包含了文章内容和标签:
{
"post_text": "enjoy the mongodb articles on java",
"tags": [
"mongodb",
"java"
]
}
1.2.4.1 使用正则表达式
以下命令使用正则表达式查找包含 java字符串的文章:
db.posts.find({post_text:{$regex:"java"}})
以上查询也可以写为/ /
,这是JavaScript中正则写法:
db.posts.find({post_text:/java/})
1.2.4.2 不区分大小写的正则表达式
如果检索需要不区分大小写,我们可以设置 $options
为 $i
以下命令将查找不区分大小写的字符串 java:
>db.posts.find({post_text:{$regex:"java",$options:"$i"}})
集合中会返回所有包含字符串 java的数据,且不区分大小写:
{
"_id" : ObjectId("53493d37d852429c10000004"),
"post_text" : "hey! this is my post on java",
"tags" : [ "java" ]
}
1.2.4.3 数组元素使用正则表达式
还可以在数组字段中使用正则表达式来查找内容。 这在标签的实现上非常有用,如果需要查找包含以 ja 开头的标签数据(va 或 jav或 java), 可以使用以下代码:
db.posts.find({tags:{$regex:"jav"}})
1.2.4.4 优化正则表达式查询
如果文档中字段设置了索引,那么使用索引相比于正则表达式匹配查找所有的数据查询速度更快。
如果正则表达式是前缀表达式,所有匹配的数据将以指定的前缀字符串为开始。例如: 如果正则表达式为 ^tut
,查询语句将查找以 tut
为开头的字符串。
这里面使用正则表达式需要注意:
正则表达式中使用变量。一定要使用eval
将组合的字符串进行转换,不能直接将字符串拼接后传入给表达式。否则没有报错信息,只是结果为空!实例如下:
var name=eval("/" + 变量值key +"/i");
以下是模糊查询包含title关键词, 且不区分大小写:
title:eval("/"+title+"/i")
等同于 title:{$regex:title,$Option:"$i"}
1.3 游标
1.3.1 定义
通俗的说,游标不是查询结果,而是查询的返回资源,或者接口,通过这个接口,可以逐条读取
1.3.2 游标声明
var cursor = db.collectioName.find(query,projection);
cursor.hasNext(); 判断游标是否已经取到尽头
cursor. Next(); 取出游标的下1个单元
用while来循环游标
> var mycursor = db.bar.find({_id:{$lte:5}})
> while(mycursor.hasNext()) {
... printjson(mycursor.next());
... }
用for循环
// 声明游标
var cursor = db.goods.find();
// 循环游标
for(var doc=true;cursor.hasNext();) { printjson(cursor.next());}
也可以简写:
for(var cursor=db.goods.find(), doc=true;cursor.hasNext();) { printjson(cursor.next());}
1.3.3 操作游标
游标还有一个迭代函数,允许我们自定义回调函数来逐个处理每个单元.
cursor.forEach(回调函数);
var gettitle = function(obj) {print(obj.goods_name)}
var cursor = db.goods.find();
cursor.forEach(gettitle);
通过cursor一次性得到所有数据, 并返回数组.
var cursor = db.goods.find();
printjson(cursor.toArray()); //看到所有行
printjson(cursor.toArray()[2]); //看到第2行
注意
:不要随意使用toArray()
,原因: 会把所有的行立即以对象形式组织在内存里.可以在取出少数几行时,用此功能