MongoDB–find查询


文章目录

  • MongoDB--find查询
  • 一:指定需要返回的键
  • 二:查询条件
  • 1.范围查询
  • 2.or 查询
  • 2.1 $in 一对多匹配
  • 2.2 $nin一对多排除
  • 2.3 $or 包含多个条件
  • 2.4 $or和in连用
  • 3. $and
  • 4. $not
  • 5. 关于条件语义
  • 三:特定类型的查询
  • 1. null
  • 2. 正则表达式
  • 3. 查询数组
  • 3.1 $all多个元素匹配数组
  • 3.2 $size 查询特定长度的数组
  • 3.3 $slice操作符
  • 3.4 返回一个匹配的数组元素
  • 3.5 数组和范围查询的相互作用
  • 4. 查询内嵌文档
  • 四:$where查询
  • 五:游标
  • 1. 基本操作
  • 2. limit skip和sort
  • 3. 避免使用skip略过大量结果
  • 3.1 不用skip对结果分页
  • 3.2 随机选取文档
  • 4. 高级查询选项
  • $maxscan:integer
  • $min :document
  • $max:document
  • $showDiskLoc:true
  • 5.游标的生命周期和一致性结果问题


一:指定需要返回的键

使用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分钟没有使用,游标也会自动销毁(这个选项可以关闭)