MongoDB–find查询
一:指定需要返回的键
使用find()来进行查询,查询返回的是一个集合中文档的子集。find的第一个参数指定查询条件。第二个参数指定想要的键。
//返回所有文档
cqsm>db.coll.find()
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716c"), "x" : "aaa" }
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716d"), "x" : "b" }
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716e"), "x" : "c" }
{ "_id" : ObjectId("5dda60fb7a8eb11f45c159ab"), "eat" : 22 }
{ "_id" : ObjectId("5dda641f7a8eb11f45c159bd"), "like" : 1 }
//返回指定查询条件的文档
cqsm>db.coll.find({"x":"aaa"})
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716c"), "x" : "aaa" }
//通过find()的第二个参数指定返回的键,1是返回,0是不返回
db.coll.find({},{"x":1,"_id":0})
注意:find的第一个参数,不能引用文档中其他键的值
二:查询条件
1.范围查询
- $lt:<
- $lte:<=
- $gt:>
- $gte:>=
- $ne:!=
cqsm>db.coll.find({"eat":{"$lt":22}})
{ "_id" : ObjectId("5ddb5107c7548e63d83b2933"), "eat" : 12 }
cqsm>db.coll.find({"eat":{"$ne":22}}) //查询出eat不等于22的文档
2.or 查询
2.1 $in 一对多匹配
cqsm>db.coll.find({"x":{"$in":["aaa","c"]}})
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716c"), "x" : "aaa" }
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716e"), "x" : "c" }
2.2 $nin一对多排除
cqsm>db.coll.find({"x":{"$nin":["aaa","c"]}})
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716d"), "x" : "b" }
2.3 $or 包含多个条件
cqsm>db.coll.find({"$or":[{"x":"c"},{"eat":22}]})
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716e"), "x" : "c" }
{ "_id" : ObjectId("5dda60fb7a8eb11f45c159ab"), "eat" : 22 }
2.4 $or和in连用
cqsm>db.coll.find({"$or":[{"x":"c"},{"eat":{"$in":[12,33]}}]})
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716e"), "x" : "c" }
{ "_id" : ObjectId("5ddb50ffc7548e63d83b2932"), "eat" : 33 }
{ "_id" : ObjectId("5ddb5107c7548e63d83b2933"), "eat" : 12 }
3. $and
$and和or是不同的,or满足其中一个或者多个,and是都满足
cqsm>db.coll.find({"$and":[{ "_id" : ObjectId("5dda13e73ee0f76ee97c716c")},{"x":"aaa"}]})
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716c"), "x" : "aaa" }
4. $not
$not是元条件句可以使用咋其他任何条件之上,顺序是在其他条件之前,查询字段之后
cqsm>db.coll.find({"eat":{"$not":{"$in":[22,33,12]}}})
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716c"), "x" : "aaa" }
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716d"), "x" : "b" }
{ "_id" : ObjectId("5dda13e73ee0f76ee97c716e"), "x" : "c" }
{ "_id" : ObjectId("5dda641f7a8eb11f45c159bd"), "like" : 1 }
5. 关于条件语义
- 修改器中一个键不能对应多个修改器,但是查询没有限制;
- $in和nin,lt,not位置处于内层文档,而and和or处于外层文档;
三:特定类型的查询
1. null
如果文档中含有null,可以直接匹配到,但是如果没有,还会返回确实这个键的所有文档。
2. 正则表达式
MongDB使用的是PCRE库来匹配正则表达式;
MongDB可以为前缀表达式(比如/^joey/)查询创建索引,这种查询会比较高效;
正则表达式可以匹配自身;
字符 | 描述 |
\ | 将下一个字符标记为一个特殊字符,或一个原义字符,或一个向后引用,或一个八进制转义符。例如,”\n”匹配一个换行符。 |
^ | 匹配输入字符串的开始位置。 |
$ | 匹配输入字符串的结束位置。 |
* | 匹配前面的子表达式零次或多次,等价于{0,} |
+ | 匹配前面的子表达式一次或多次,等价于{1,} |
? | 匹配前面的子表达式零次或一次,等价于{0,1} |
? | 当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少地匹配所搜索的字符串,而默认的贪婪模式则尽可能多地匹配所搜索的字符串。例如,对于字符串”oooo”,”o+?”将匹配单个”o”,而”o+”将匹配所有的”o”。 |
{n} | N是一个非负整数,匹配确定的n次。 |
{n,} | N是一个非负整数,至少匹配n次。 |
{n,m} | M和n均为非负整数,其中n<=m,最少匹配n次且最多匹配m次。 |
. | 匹配除”\n”之外的任何单个字符。要匹配包括”\n”在内的任何字符,请使用像”[.\n]”的模式 |
(pattern) | 匹配pattern并获取这一匹配。 |
(?:pattern) | 匹配pattern但不获取匹配结果。这在使用“或”字符(|)来组合一个模式的各个部分是很有用的。例如:’industry|industries’就可以用’industr(?:y|ies)’代替 |
(?=pattern) | 正向预查,在任何匹配pattern的字符串开始处匹配查找字符串。例如:”Windows(?=95|98|NT|2000)”能匹配”Windows2000”中的”Windows”,但不能匹配”Windows3.1”中的”Windows”。 |
(?!pattern) | 负向预查,在任何不匹配pattern的字符串开始处匹配查找字符串。例如:”Windows(?!95|98|NT|2000)”能匹配”Windows3.1”中的”Windows”,但不能匹配”Windows2000”中的”Windows”。 |
x|y | 匹配x或y。 |
[xyz] | 字符集合,匹配所包含的任何一个字符。 |
[^xyz] | 负值字符集合,匹配未包含的任意字符。 |
[a-z] | 字符范围,匹配指定范围内的任意字符。 |
[^a-z] | 负值字符范围,匹配任何不在指定范围内的任意字符。 |
\b | 匹配一个单词边界,也就是单词和空格间的位置。 |
\B | 匹配非单词边界。 |
\cx | 匹配由x指明的控制字符。X的值必须为A-Z或a-z之间 |
\d | 匹配一个数字字符。等价于[0-9] |
\D | 匹配一个非数字字符。等价于[^0-9] |
\f | 匹配一个换页符。等价于\x0c和\cL |
\n | 匹配一个换行符。等价于\x0a和\cJ |
\r | 匹配一个回车符。等价于\x0d和\cM |
\s | 匹配任何空白字符,包括空格、制表符、换页符等。 |
\S | 匹配任何非空白符。 |
\t | 匹配一个制表符 |
\w | 匹配包括下划线的任何单词字符。等价于[a-zA-Z0-9_] |
\W | 匹配任何非单词字符。 |
\xn | 匹配n,其中n为十六进制转义值。例如”\x41”匹配”A”。 |
\num | 匹配num,其中num是一个正整数。对所获取的匹配的引用。例如:”(.)\1” |
3. 查询数组
3.1 $all多个元素匹配数组
插入数组
db.coll.insert([{"_id":1,"fruit":["apple","banana","peach"]}, {"_id":2,"fruit":["apple","lalala","ooooo"]},
{"_id":3,"fruit":["apple","aaaaa","bbbbb"]}])
使用$all匹配多个数组中元素
cqsm>db.coll.find({"fruit":{"$all":["apple","peach"]}})
{ "_id" : 1, "fruit" : [ "apple", "banana", "peach" ] }
3.2 $size 查询特定长度的数组
cqsm>db.coll.find({"fruit":{"$size":3}})
{ "_id" : 1, "fruit" : [ "apple", "banana", "peach" ] }
{ "_id" : 2, "fruit" : [ "apple", "lalala", "ooooo" ] }
{ "_id" : 3, "fruit" : [ "apple", "aaaaa", "bbbbb" ] }
cqsm>
由于$size不能喝gt lt 等连用,于是可以在文档中添加一个用来计数的size键,每次向数组中添加元素的时候就将size增加1
db.coll.update({"_id":1},{"$push":{"fruit":"ccccc"},"$inc":{"size":1}})
db.coll.update({"_id":1},{"$push":{"fruit":"fffff"},"$inc":{"size":1}})
查询的时候就可以这样查:
cqsm>db.coll.find({"size":{"$gte":1}})
{ "_id" : 1, "fruit" : [ "apple", "banana", "peach", "ccccc", "fffff" ], "size" : 2 }
3.3 $slice操作符
"$slice"可以指定偏移量以及希望返回的元素数量,返回的是所有的键不是指定的键
有如下文档:
{ "_id" : 1, "fruit" : [ "apple", "banana", "peach", "ccccc", "fffff" ], "size" : 2 }
返回数组中前两个
cqsm>db.coll.findOne({"_id" : 1},{"fruit":{"$slice":2}})
{ "_id" : 1, "fruit" : [ "apple", "banana" ], "size" : 2 }
返回数组中后两个
cqsm>db.coll.findOne({"_id" : 1},{"fruit":{"$slice":-2}})
{ "_id" : 1, "fruit" : [ "ccccc", "fffff" ], "size" : 2 }
返回数组中间两个,下标从0开始
cqsm>db.coll.findOne({"_id" : 1},{"fruit":{"$slice":[1,2]}})
{ "_id" : 1, "fruit" : [ "banana", "peach" ], "size" : 2 }
3.4 返回一个匹配的数组元素
在不知道数组下标的情况下,可以使用$从匹配的文档中返回一个指定的元素
db.coll.find({"comments.name":"bob"},{"comments.$":1})
3.5 数组和范围查询的相互作用
由于范围查询对于数组来说,只要数组中有任何一个条件符合就会被返回,显然这是不合理的。
可以在要比较的字段上创建索引,然后使用min()和max()将查询条件遍历的索引范围限制为"gt"和"lt"
db.text.find({"x":{"$gt":10,"$lt":20}.min({"x":10}).max("x":20)})
4. 查询内嵌文档
查询整个内嵌文档
查询内嵌文档,如果不做其他的操作,那么查询文档就必须完全匹配才能查询得到
有如下数据
{
"_id" : ObjectId("5ddb8c64c7548e63d83b2939"),
"neiqian" : {
"_id" : 4,
"name" : "zs",
"age" : 12,
"sex" : "n"
}
}
查询整个文档:
cqsm>db.coll.find({"neiqian":{ "_id" : 4,"name" : "zs","age" : 12,"sex" : "n"}})
{ "_id" : ObjectId("5ddb8c64c7548e63d83b2939"), "neiqian" : { "_id" : 4, "name" : "zs", "age" : 12, "sex" : "n" } }
可以通过" . "连接,针对键查询,查询文档就不用写文档内的全部内容了
cqsm>db.coll.find({"neiqian.name":"zs"})
{ "_id" : ObjectId("5ddb8c64c7548e63d83b2939"), "neiqian" : { "_id" : 4, "name" : "zs", "age" : 12, "sex" : "n" } }
通过"$elemMatch",将限定条件分组,仅当需要对一个内嵌文档的多个键操作的时候才会用得上
db.coll.find({"neiqian":{"$elemMatch":{"name":"zs","age":12}}})
四:$where查询
where可以执行能人js语句,所以几乎可以做任何事情,但是这很危险而且效率不高,所以只有在没有办法的时候才去使用。
db.coll.find({"$where":function(){
for(var c in this){
for(var b in this){
if(c!=b && this[c]==this[b]){
return true;
}
}
}
return false;
}})
函数返回true,文档就作为结果集的一部分返回,函数返回false,就不返回。
五:游标
数据库使用游标返回find的执行结果。
1. 基本操作
1、插入数据
for(var i=0;i<10000;i++){
db.shop.insert({_id:i+1,name:"shop"+i,age:20+i})
}
2、查看数据数
db.shop.find().count()
3、获取游标、判断是否还存在数据
#获取游标,并存放在mycursor变量中
var mycursor = db.shop.find()
#以json形式打印一条
printjson(mycursor.next())
#查看游标是否到了尾部
printjson(mycursor.hasNext())
4、游标跳过
#skip()--->游标跳到9000位置
var mycursor = db.shop.find().skip(9000)
#limit()--->函数使用,跳过9000条,显示后面10条
db.shop.find().skip(9000).limit(10)
5、游标高级操作函数
#创建一个游标
var mycursor = db.shop.find()
#对游标获取的对象(obj)进行遍历(forEach)打印(printjson)
mycursor.forEach(function(obj){printjson(obj)})
#查看当前批次剩余的未被迭代的文档数量
mycursor.objLeftBatch()
#对文档按age进行降序
语法:sort({filed:1/-1}) ;1,升序,-1降序
db.user.find().sort({age:-1})
#设置游标迭代次数(即每页显示的记录数)
DBQuery.shellBatchSize = 10 #eg:执行db.user.find(),显示10条数据
#只显示一条文档
db.shop.findOne()
#游标的操作函数有以下几个,可自行操作
hasNext 判断是否还有更多的文档 sort 对查询结果进行排序
next 用来获取下一条文档 objsLeftInBatch 查看当前批次剩余的未被迭代的文档数量
toArray 将查询结果放到数组中 addOption 为游标设置辅助选项,修改游标的默认行为
count 获取结果集中总的文档数量 hint 为查询强制使用指定索引
limit 限制结果返回数量 explain 用于获取查询执行过程报告
skip 跳过指定数目的文档 snapshot 对查询结果使用快照
2. limit skip和sort
limit可以限定返回结果的数量,skip会略过指定数量的结果
cqsm>db.shop.find().limit(5)
{ "_id" : 1, "name" : "shop0", "age" : 20 }
{ "_id" : 2, "name" : "shop1", "age" : 21 }
{ "_id" : 3, "name" : "shop2", "age" : 22 }
{ "_id" : 4, "name" : "shop3", "age" : 23 }
{ "_id" : 5, "name" : "shop4", "age" : 24 }
sort()接受一个对象作为参数,参数是键值对的形式,键是文档的键名,值是1或者-1,1代表升序,-1代表降序。还可以指定多个键,分别排序。
db.shop.find().sort({"username":1,"age":-1})
MongoDB处理不同类型的数据是有一定的顺序的;
- 最小值
- null
- 数子(整形,长整型,双精度型)
- 字符串
- 对象/文档
- 数组
- 二进制数据
- 对象ID
- 布尔型
- 日期型
- 时间戳
- 正则表达式
- 最大值
3. 避免使用skip略过大量结果
3.1 不用skip对结果分页
如下虽然语法可以,但是当数据量比较大的时候速度会很慢
var page=db.coll.find().limit()
var page1=db.coll.find().skip(100).limit(100)
var page2=db.coll.find().skip(200).limit(100)
3.2 随机选取文档
可以采用随机数作为查询条件的方法,随机查找,当然插入文档的时候可以添加一个随机数键。
4. 高级查询选项
MongDB查询并不是将查询文档直接发给数据库,而是先将查询封装在一个更大的文档中,shell会把查询转换成$query…等等
一些有用的辅助函数:
$maxscan:integer
指定本次扫描中扫描文档数量的上限,如下返回的结果一模一样,我也不知道为什么
db.shop.find()._addSpecial("$maxscan")
db.shop.find()._addSpecial("$maxscan",20)
db.shop.find()._addSpecial("$maxscan",6)
$min :document
$max:document
$showDiskLoc:true
在查询结果中添加一个"$diskLoc"字段显示该条结果在磁盘上的位置
db.shop.find()._addSpecial("$showDiskLoc",true)
5.游标的生命周期和一致性结果问题
程序获取一定量的文档处理,当游标范围内某些文档因为体积增大移动位置(一般是移动到末尾),当游标移动有可能返回那些由于体积变大无法放回原位置的文档。解决这个问题,可以对查询进行快照,查询就在"_id"索引上遍历执行,这样就可以保证每个文档只被返回一次。但是这样会导致,查询变慢。
db.coll.find().snapshot()
关于游标的生命周期:
1.游标完成匹配结果的迭代的时候,游标会清除自身;
2.客户端的游标不在作用域的时候,驱动程序会给服务器发送消息,销毁游标;
3.如果一个游标10分钟没有使用,游标也会自动销毁(这个选项可以关闭)