1. 程式人生 > 其它 >mongo-03-查詢文件

mongo-03-查詢文件

技術標籤:005-mongo實戰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 '}', got 'EOF' at end of input: …文件 `{<field>:{in:[,…]}}`
  • KaTeX parse error: Expected '}', got 'EOF' at end of input: …文件 `{<field>:{
    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" }
> 

[慕課手記同步:mongo-03-查詢文件] https://www.imooc.com/article/314364


歡迎關注文章同步公眾號"黑桃"

在這裡插入圖片描述