为了账号安全,请及时绑定邮箱和手机立即绑定

mongo-03-查询文档

标签:
MongoDB

1. find 读取文档

db.<collection>.find(<query>,<projection>)

  • query : 定义了读取操作时筛选文档的条件
  • projection : 定义了对读取结果进行的投射,也就是只返回某些字段

1.1 读取文档

不进行筛选和投射

> db.user.find()
{ "_id" : "1", "money" : 1000, "name" : "刘一" }
{ "_id" : "2", "money" : 1000, "name" : "陈二" }
{ "_id" : "3", "money" : 1000, "name" : "张三" }
{ "_id" : "4", "money" : 1000, "name" : "李四" }
{ "_id" : "5", "money" : 1000, "name" : "王五" }
{ "_id" : "6", "money" : 1000, "name" : "赵六" }
{ "_id" : "7", "money" : 1000, "name" : "孙七" }
{ "_id" : ObjectId("5fff6a78025e5d9ea86e18cc"), "money" : 1000, "name" : "周八" }
{ "_id" : { "age" : 18, "gender" : "男" }, "money" : 1000, "name" : "吴九" }
> 

查询 name 为 张三的文档

> db.user.find({"name":"张三"})
{ "_id" : "3", "money" : 1000, "name" : "张三" }
> 

1.2 pretty 格式化显示文档

> db.user.find().pretty()
{ "_id" : "1", "money" : 1000, "name" : "刘一" }
{ "_id" : "2", "money" : 1000, "name" : "陈二" }
{ "_id" : "3", "money" : 1000, "name" : "张三" }
{ "_id" : "4", "money" : 1000, "name" : "李四" }
{ "_id" : "5", "money" : 1000, "name" : "王五" }
{ "_id" : "6", "money" : 1000, "name" : "赵六" }
{ "_id" : "7", "money" : 1000, "name" : "孙七" }
{
	"_id" : ObjectId("5fff6a78025e5d9ea86e18cc"),
	"money" : 1000,
	"name" : "周八"
}
{
	"_id" : {
		"age" : 18,
		"gender" : "男"
	},
	"money" : 1000,
	"name" : "吴九"
}
> 

1.3 筛选文档:比较操作符

{<field>:{$<operator>:<value>}}

比较操作符 $<operator>

  • $eq : 匹配字段值相等的文档
  • $ne : 匹配字段值不相等的文档
  • $gt : 匹配字段值大于查询值的文档
  • $gte : 匹配字段值大于或等于查询值的文档
  • $lt : 匹配字段值小于查询值的文档
  • $lte : 匹配字段值小于或等于查询值的文档
  • KaTeX parse error: Expected 'EOF', got '匹' at position 6: in : 匹̲配字段值与任一查询值相等的文档…in:[,…]}}`
  • KaTeX parse error: Expected 'EOF', got '匹' at position 7: nin : 匹̲配字段值与任一查询值不相等的文…nin:[,…]}}`

查询 money 等于 1000的文档,和查询 money 大于 1000的文档

# 查询 money 等于 1000的文档
> db.user.find({"money":{$eq: 1000}})
{ "_id" : "1", "money" : 1000, "name" : "刘一" }
{ "_id" : "2", "money" : 1000, "name" : "陈二" }
{ "_id" : "3", "money" : 1000, "name" : "张三" }
{ "_id" : "4", "money" : 1000, "name" : "李四" }
{ "_id" : "5", "money" : 1000, "name" : "王五" }
{ "_id" : "6", "money" : 1000, "name" : "赵六" }
{ "_id" : "7", "money" : 1000, "name" : "孙七" }
{ "_id" : ObjectId("5fff6a78025e5d9ea86e18cc"), "money" : 1000, "name" : "周八" }
{ "_id" : { "age" : 18, "gender" : "男" }, "money" : 1000, "name" : "吴九" }
# 查询 money 大于 1000的文档
> db.user.find({"money":{$gt: 1000}})
> 

查询 name 为 张三或者赵六的文档

> db.user.find({"name":{$in: ["张三","赵六"]}})
{ "_id" : "3", "money" : 1000, "name" : "张三" }
{ "_id" : "6", "money" : 1000, "name" : "赵六" }
> 

1.3 筛选文档:逻辑操作符

逻辑操作符 $<operator>

  • $not 匹配筛选条件不成立的文档
  • $and 匹配多个筛选条件全部成立的文档
  • $or 匹配至少一个筛选条件成立的文档
  • $nor 匹配多个筛选条件全部不成立的文档

1.3.1 $and 匹配多个筛选条件全部成立的文档

{$and: [{<expression1>},{<expression2>},...,{<expressionN>}]}

查询 money<2000 , name = 张三 的文档

> db.user.find({$and: [{"money":{$lt:2000}},{"name":"张三"}]})
{ "_id" : "3", "money" : 1000, "name" : "张三" }
> 

字段名可以用双引号引起来,也可以不用双引号。

当筛选条件应用在不同的字段上时,可以省略 $and 操作符
查询 money<2000 , name = 张三 的文档,省略 $and

> db.user.find({money:{$lt:2000},name:"张三"})
{ "_id" : "3", "money" : 1000, "name" : "张三" }
> 

当筛选条件应用在同一个字段上时,也可以简化命令
查询 money > 500 且 money < 2000 的文档

> db.user.find({money:{$gt:500, $lt:2000}})
{ "_id" : "1", "money" : 1000, "name" : "刘一" }
{ "_id" : "2", "money" : 1000, "name" : "陈二" }
{ "_id" : "3", "money" : 1000, "name" : "张三" }
{ "_id" : "4", "money" : 1000, "name" : "李四" }
{ "_id" : "5", "money" : 1000, "name" : "王五" }
{ "_id" : "6", "money" : 1000, "name" : "赵六" }
{ "_id" : "7", "money" : 1000, "name" : "孙七" }
{ "_id" : ObjectId("5fff6a78025e5d9ea86e18cc"), "money" : 1000, "name" : "周八" }
{ "_id" : { "age" : 18, "gender" : "男" }, "money" : 1000, "name" : "吴九" }
> 

1.3.2 $or 匹配至少一个筛选条件成立的文档

{$or: [{<expression1>},{<expression2>},...,{<expressionN>}]}

查询 name 为 张三 或者 李四 的文档

> db.user.find({$or: [{"name":"张三"},{"name":"李四"}]})
{ "_id" : "3", "money" : 1000, "name" : "张三" }
{ "_id" : "4", "money" : 1000, "name" : "李四" }
> 

上面的操作等同于

> db.user.find({name:{$in:["张三","李四"]}})
{ "_id" : "3", "money" : 1000, "name" : "张三" }
{ "_id" : "4", "money" : 1000, "name" : "李四" }
> 

1.3.3 $nor 匹配多个筛选条件全部不成立的文档

{$nor: [{<expression1>},{<expression2>},...,{<expressionN>}]}

查询 name 不为 张三 和 李四 的文档

> db.user.find({$nor: [{"name":"张三"},{"name":"李四"}]})
{ "_id" : "1", "money" : 1000, "name" : "刘一" }
{ "_id" : "2", "money" : 1000, "name" : "陈二" }
{ "_id" : "5", "money" : 1000, "name" : "王五" }
{ "_id" : "6", "money" : 1000, "name" : "赵六" }
{ "_id" : "7", "money" : 1000, "name" : "孙七" }
{ "_id" : ObjectId("5fff6a78025e5d9ea86e18cc"), "money" : 1000, "name" : "周八" }
{ "_id" : { "age" : 18, "gender" : "男" }, "money" : 1000, "name" : "吴九" }
>

1.4 字段操作符

1.4.1 $exists 匹配包含查询字段的文档

{field: {$exists: <boolean>}}

查询包含 name 字段的文档

> db.user.find({name: {$exists: true}})
{ "_id" : "1", "money" : 1000, "name" : "刘一" }
{ "_id" : "2", "money" : 1000, "name" : "陈二" }
{ "_id" : "3", "money" : 1000, "name" : "张三" }
{ "_id" : "4", "money" : 1000, "name" : "李四" }
{ "_id" : "5", "money" : 1000, "name" : "王五" }
{ "_id" : "6", "money" : 1000, "name" : "赵六" }
{ "_id" : "7", "money" : 1000, "name" : "孙七" }
{ "_id" : ObjectId("5fff6a78025e5d9ea86e18cc"), "money" : 1000, "name" : "周八" }
{ "_id" : { "age" : 18, "gender" : "男" }, "money" : 1000, "name" : "吴九" }

查询包含 phone 字段的文档

> db.user.find({phone: {$exists: true}})
> 

1.4.2 $type 匹配字段类型符合查询值的文档

查询 _id 为 string 类型的文档

> db.user.find({_id: {$type: "string"}})
{ "_id" : "1", "money" : 1000, "name" : "刘一" }
{ "_id" : "2", "money" : 1000, "name" : "陈二" }
{ "_id" : "3", "money" : 1000, "name" : "张三" }
{ "_id" : "4", "money" : 1000, "name" : "李四" }
{ "_id" : "5", "money" : 1000, "name" : "王五" }
{ "_id" : "6", "money" : 1000, "name" : "赵六" }
{ "_id" : "7", "money" : 1000, "name" : "孙七" }
> 

查询 _id 不为 string 类型的文档

> db.user.find({_id: {$not:{$type: "string"}}})
{ "_id" : ObjectId("5fff6a78025e5d9ea86e18cc"), "money" : 1000, "name" : "周八" }
{ "_id" : { "age" : 18, "gender" : "男" }, "money" : 1000, "name" : "吴九" }
> 

1.5 数组操作

1.5.1 $all 匹配数组字段中包含所有查询值的文档

{field: {$all: [<value1>,<value2>,..,<valueN>]}}

插入一条包含数组字段 addr 的文档,并进行 $all 匹配

# 插入一条包含数组字段 addr 的文档
> db.user.insert({"money":3000,"name":"广东人", addr: ["广州","深圳"]})
WriteResult({ "nInserted" : 1 })
# 匹配 addr 字段中包含 "广州","深圳" 的 文档
> db.user.find({addr: {$all:["广州","深圳"]}})
{ "_id" : ObjectId("5fff8fe79dbe959b53a603b6"), "money" : 3000, "name" : "广东人", "addr" : [ "广州", "深圳" ] }
# 匹配 addr 字段中包含 "广州" 的 文档
> db.user.find({addr: {$all:["广州"]}})
{ "_id" : ObjectId("5fff8fe79dbe959b53a603b6"), "money" : 3000, "name" : "广东人", "addr" : [ "广州", "深圳" ] }
# 匹配 addr 字段中包含 "广州","北京" 的 文档
> db.user.find({addr: {$all:["广州","北京"]}})
> 

1.5.2 $elemMatch 匹配数组字段中至少存在一个值满足筛选条件的文档

{field: {$elemMatch: [<query1>,<query2>,..,<queryN>]}}

查询 addr 数组字段的任意一个item 匹配是 “广州”的文档

> db.user.find({addr: {$elemMatch: {$eq: "广州"}}})
{ "_id" : ObjectId("5fff8fe79dbe959b53a603b6"), "money" : 3000, "name" : "广东人", "addr" : [ "广州", "深圳" ] }
> 

1.6 正则匹配

{field: {$regex:/pattern/, $options: "options"}}

数据准备

> db.user.insert({"money":2000,"name":"zhangsan", addr: ["广州","北京"]})
WriteResult({ "nInserted" : 1 })
> db.user.insert({"money":2000,"name":"ZHANG", addr: ["三亚","北京"]})
WriteResult({ "nInserted" : 1 })
> db.user.find()
{ "_id" : "1", "money" : 1000, "name" : "刘一" }
{ "_id" : "2", "money" : 1000, "name" : "陈二" }
{ "_id" : "3", "money" : 1000, "name" : "张三" }
{ "_id" : "4", "money" : 1000, "name" : "李四" }
{ "_id" : "5", "money" : 1000, "name" : "王五" }
{ "_id" : "6", "money" : 1000, "name" : "赵六" }
{ "_id" : "7", "money" : 1000, "name" : "孙七" }
{ "_id" : ObjectId("5fff6a78025e5d9ea86e18cc"), "money" : 1000, "name" : "周八" }
{ "_id" : { "age" : 18, "gender" : "男" }, "money" : 1000, "name" : "吴九" }
{ "_id" : ObjectId("5fff8fe79dbe959b53a603b6"), "money" : 3000, "name" : "广东人", "addr" : [ "广州", "深圳" ] }
{ "_id" : ObjectId("5fff955d3f6d5ed2fcce4132"), "money" : 2000, "name" : "zhangsan", "addr" : [ "广州", "北京" ] }
{ "_id" : ObjectId("5fff95783f6d5ed2fcce4133"), "money" : 2000, "name" : "ZHANG", "addr" : [ "三亚", "北京" ] }
> 

查询 name 以 zhang 开头的文档

> db.user.find({name: {$regex: /^zhang/}})
{ "_id" : ObjectId("5fff955d3f6d5ed2fcce4132"), "money" : 2000, "name" : "zhangsan", "addr" : [ "广州", "北京" ] }
>

查询 name 以 zhang 开头的文档,并忽略大小写

> db.user.find({name: {$regex: /^zhang/, $options: "i"}})
{ "_id" : ObjectId("5fff955d3f6d5ed2fcce4132"), "money" : 2000, "name" : "zhangsan", "addr" : [ "广州", "北京" ] }
{ "_id" : ObjectId("5fff95783f6d5ed2fcce4133"), "money" : 2000, "name" : "ZHANG", "addr" : [ "三亚", "北京" ] }
> 

2. 文档游标

db.collection.find() 返回一个文档集合游标(cursor)。

游标常用函数有:

  • cursor.limit()
  • cursor.skip()
  • cursor.count()
  • cursor.sort()

2.1 cursor.limit(<number>) 限制返回结果的最大数量

只返回前3条记录

> db.user.find().limit(3)
{ "_id" : "1", "money" : 1000, "name" : "刘一" }
{ "_id" : "2", "money" : 1000, "name" : "陈二" }
{ "_id" : "3", "money" : 1000, "name" : "张三" }
> 

limit(0) 不做数量限制,返回所有

> db.user.find().limit(0)
{ "_id" : "1", "money" : 1000, "name" : "刘一" }
{ "_id" : "2", "money" : 1000, "name" : "陈二" }
{ "_id" : "3", "money" : 1000, "name" : "张三" }
{ "_id" : "4", "money" : 1000, "name" : "李四" }
{ "_id" : "5", "money" : 1000, "name" : "王五" }
{ "_id" : "6", "money" : 1000, "name" : "赵六" }
{ "_id" : "7", "money" : 1000, "name" : "孙七" }
{ "_id" : ObjectId("5fff6a78025e5d9ea86e18cc"), "money" : 1000, "name" : "周八" }
{ "_id" : { "age" : 18, "gender" : "男" }, "money" : 1000, "name" : "吴九" }
{ "_id" : ObjectId("5fff8fe79dbe959b53a603b6"), "money" : 3000, "name" : "广东人", "addr" : [ "广州", "深圳" ] }
{ "_id" : ObjectId("5fff955d3f6d5ed2fcce4132"), "money" : 2000, "name" : "zhangsan", "addr" : [ "广州", "北京" ] }
{ "_id" : ObjectId("5fff95783f6d5ed2fcce4133"), "money" : 2000, "name" : "ZHANG", "addr" : [ "三亚", "北京" ] }
> 

2.2 cursor.skip(<offset>) 跳过前面几条记录

跳过前3条记录

> db.user.find().skip(3)
{ "_id" : "4", "money" : 1000, "name" : "李四" }
{ "_id" : "5", "money" : 1000, "name" : "王五" }
{ "_id" : "6", "money" : 1000, "name" : "赵六" }
{ "_id" : "7", "money" : 1000, "name" : "孙七" }
{ "_id" : ObjectId("5fff6a78025e5d9ea86e18cc"), "money" : 1000, "name" : "周八" }
{ "_id" : { "age" : 18, "gender" : "男" }, "money" : 1000, "name" : "吴九" }
{ "_id" : ObjectId("5fff8fe79dbe959b53a603b6"), "money" : 3000, "name" : "广东人", "addr" : [ "广州", "深圳" ] }
{ "_id" : ObjectId("5fff955d3f6d5ed2fcce4132"), "money" : 2000, "name" : "zhangsan", "addr" : [ "广州", "北京" ] }
{ "_id" : ObjectId("5fff95783f6d5ed2fcce4133"), "money" : 2000, "name" : "ZHANG", "addr" : [ "三亚", "北京" ] }
> 

2.3 cursor.count(<applySkipLimit>) 统计数量

默认情况下,<applySkipLimit>为false,即 cursor.count() 不会考虑 cursor.skip() 和 cursor.limit() 的效果

默认情况下,<applySkipLimit>为false
limit(3),查看 <applySkipLimit>为false和true,count() 的结果

# 默认情况下,applySkipLimit = false
> db.user.find().limit(3).count()
12
# applySkipLimit = true
> db.user.find().limit(3).count(true)
3
# applySkipLimit = false
> db.user.find().limit(3).count(false)
12
> 

在不提供筛选条件时,cursor.count() 会从集合的元数据 Metadata中取得结果。
当数据库分布式结构较为复杂时,元数据中的文档数量可能不准确,在这种情况下,应该避免应用不提供筛选条件的 cursor.count() 函数,而是用聚合管道来计算文档数量。

2.4 cursor.sort() 排序

cursor.sort(<document>)
这里的 <document> 定义了排序的要求
{field: ordering}

  • 1 : 表示由小到大的正向排序
  • -1 : 表示逆向排序

按照 money 逆向排序从大到小,name 按字母正向排序的方式排列

> db.user.find().sort({money: -1,name: 1})
{ "_id" : ObjectId("5fff8fe79dbe959b53a603b6"), "money" : 3000, "name" : "广东人", "addr" : [ "广州", "深圳" ] }
{ "_id" : ObjectId("5fff95783f6d5ed2fcce4133"), "money" : 2000, "name" : "ZHANG", "addr" : [ "三亚", "北京" ] }
{ "_id" : ObjectId("5fff955d3f6d5ed2fcce4132"), "money" : 2000, "name" : "zhangsan", "addr" : [ "广州", "北京" ] }
{ "_id" : "1", "money" : 1000, "name" : "刘一" }
{ "_id" : { "age" : 18, "gender" : "男" }, "money" : 1000, "name" : "吴九" }
{ "_id" : ObjectId("5fff6a78025e5d9ea86e18cc"), "money" : 1000, "name" : "周八" }
{ "_id" : "7", "money" : 1000, "name" : "孙七" }
{ "_id" : "3", "money" : 1000, "name" : "张三" }
{ "_id" : "4", "money" : 1000, "name" : "李四" }
{ "_id" : "5", "money" : 1000, "name" : "王五" }
{ "_id" : "6", "money" : 1000, "name" : "赵六" }
{ "_id" : "2", "money" : 1000, "name" : "陈二" }
> 

2.5 cursor.sort()、cursor.skip()、cursor.limit()执行顺序

cursor.skip()在cursor.limit()之前执行

无论如何调换 skip() 和 limit() 的顺序,都是先执行 skip,再执行 limit

> db.user.find().limit(3).skip(1)
{ "_id" : "2", "money" : 1000, "name" : "陈二" }
{ "_id" : "3", "money" : 1000, "name" : "张三" }
{ "_id" : "4", "money" : 1000, "name" : "李四" }
> db.user.find().skip(1).limit(3)
{ "_id" : "2", "money" : 1000, "name" : "陈二" }
{ "_id" : "3", "money" : 1000, "name" : "张三" }
{ "_id" : "4", "money" : 1000, "name" : "李四" }
> 

cursor.sort()在cursor.skip()和cursor.limit()之前执行

> db.user.find().limit(4).skip(1).sort({money: -1,_id: 1})
{ "_id" : ObjectId("5fff955d3f6d5ed2fcce4132"), "money" : 2000, "name" : "zhangsan", "addr" : [ "广州", "北京" ] }
{ "_id" : ObjectId("5fff95783f6d5ed2fcce4133"), "money" : 2000, "name" : "ZHANG", "addr" : [ "三亚", "北京" ] }
{ "_id" : "1", "money" : 1000, "name" : "刘一" }
{ "_id" : "2", "money" : 1000, "name" : "陈二" }
> 

3. 文档投影

db.collection.find(<query>,<projection>)
不使用投影时,db.collection.find() 返回符合筛选条件的完整文档,而使用投影可以有选择性地返回文档中的部分字段

{field: inclusion}

  • 1 : 表示返回字段,
  • 0 : 表示不返回字段

只返回 name 字段,默认情况下 _id 字段都会返回

> db.user.find({},{name: 1})
{ "_id" : "1", "name" : "刘一" }
{ "_id" : "2", "name" : "陈二" }
{ "_id" : "3", "name" : "张三" }
{ "_id" : "4", "name" : "李四" }
{ "_id" : "5", "name" : "王五" }
{ "_id" : "6", "name" : "赵六" }
{ "_id" : "7", "name" : "孙七" }
{ "_id" : ObjectId("5fff6a78025e5d9ea86e18cc"), "name" : "周八" }
{ "_id" : { "age" : 18, "gender" : "男" }, "name" : "吴九" }
{ "_id" : ObjectId("5fff8fe79dbe959b53a603b6"), "name" : "广东人" }
{ "_id" : ObjectId("5fff955d3f6d5ed2fcce4132"), "name" : "zhangsan" }
{ "_id" : ObjectId("5fff95783f6d5ed2fcce4133"), "name" : "ZHANG" }
> 

只返回 name 字段,不包含 _id 字段

> db.user.find({},{name: 1,_id: 0})
{ "name" : "刘一" }
{ "name" : "陈二" }
{ "name" : "张三" }
{ "name" : "李四" }
{ "name" : "王五" }
{ "name" : "赵六" }
{ "name" : "孙七" }
{ "name" : "周八" }
{ "name" : "吴九" }
{ "name" : "广东人" }
{ "name" : "zhangsan" }
{ "name" : "ZHANG" }
> 

除了文档主键外,不可以在投影文档中混合使用包含和不包含两种投影操作

> db.user.find({},{name: 1,_id: 0,money: 0})
Error: error: {
	"ok" : 0,
	"errmsg" : "Cannot do exclusion on field money in inclusion projection",
	"code" : 31254,
	"codeName" : "Location31254"
}
> db.user.find({},{name: 1,_id: 0,money: 1})
{ "money" : 1000, "name" : "刘一" }
{ "money" : 1000, "name" : "陈二" }
{ "money" : 1000, "name" : "张三" }
{ "money" : 1000, "name" : "李四" }
{ "money" : 1000, "name" : "王五" }
{ "money" : 1000, "name" : "赵六" }
{ "money" : 1000, "name" : "孙七" }
{ "money" : 1000, "name" : "周八" }
{ "money" : 1000, "name" : "吴九" }
{ "money" : 3000, "name" : "广东人" }
{ "money" : 2000, "name" : "zhangsan" }
{ "money" : 2000, "name" : "ZHANG" }
> 
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消