MongoDB的查詢操作

1. 前言
在這篇文章中,我們將學習如何查詢mongoDB中的數據。當我們把數據存儲在mongoDB以后,我們需要把數據查詢出來。畢竟CRUD操作中,查詢操作在我們系統中是我們應用比較頻繁的操作。我們需要應對不同的業務需求,構造合適的查詢條件去查詢我們想要的數據。我們需要去學習mongoDB給我們提供了哪些查詢相關的語法和功能。在這里,我們使用mongodb自帶的mongo shell( mongo shell是一個javascript環境的mongodb客戶端,支持js語法 )來學習。
2. 準備
在開始之前,我們需要準備一下實驗用的數據:
// 啟動mongo shell客戶端
$ mongo
// 在這里我們使用test數據庫,如果沒有這個數據庫,會自動創建
> use test
// 在users collection中插入6條用戶數據
> db.users.insertMany(
[
{
_id: 1,
name: "sue",
age: 19,
type: 1,
status: "P",
favorites: { artist: "Picasso", food: "pizza" },
finished: [ 17, 3 ],
badges: [ "blue", "black" ],
points: [
{ points: 85, bonus: 20 },
{ points: 85, bonus: 10 }
]
},
{
_id: 2,
name: "bob",
age: 42,
type: 1,
status: "A",
favorites: { artist: "Miro", food: "meringue" },
finished: [ 11, 25 ],
badges: [ "green" ],
points: [
{ points: 85, bonus: 20 },
{ points: 64, bonus: 12 }
]
},
{
_id: 3,
name: "ahn",
age: 22,
type: 2,
status: "A",
favorites: { artist: "Cassatt", food: "cake" },
finished: [ 6 ],
badges: [ "blue", "red" ],
points: [
{ points: 81, bonus: 8 },
{ points: 55, bonus: 20 }
]
},
{
_id: 4,
name: "xi",
age: 34,
type: 2,
status: "D",
favorites: { artist: "Chagall", food: "chocolate" },
finished: [ 5, 11 ],
badges: [ "red", "black" ],
points: [
{ points: 53, bonus: 15 },
{ points: 51, bonus: 15 }
]
},
{
_id: 5,
name: "xyz",
age: 23,
type: 2,
status: "D",
favorites: { artist: "Noguchi", food: "nougat" },
finished: [ 14, 6 ],
badges: [ "orange" ],
points: [
{ points: 71, bonus: 20 }
]
},
{
_id: 6,
name: "abc",
age: 43,
type: 1,
status: "A",
favorites: { food: "pizza", artist: "Picasso" },
finished: [ 18, 12 ],
badges: [ "black", "blue" ],
points: [
{ points: 78, bonus: 8 },
{ points: 57, bonus: 7 }
]
}
]
)
View Code
3. 基本查詢
MongoDB提供了 db.collection.find() 方法來執行查詢操作。find方法接受兩個參數:一個查詢條件,一個是投影的字段。這兩個參數都不是必須的,如果省略了查詢條件,則默認列出collection中的所有文檔。
db.users.find()
// 這個和上面的語句是等價的
db.users.find({})
3.1 等值查詢
通過find()方法來執行等值查詢的時候,可以通過 { <field>:<value>} 的方式來指定查詢條件,這個條件表示在collection中查詢滿足field的值為value的所有文檔。假設我們需要查找所有status是'A'的用戶,我們可以這么查詢:
db.users.find({status: 'A'})
查詢結果
{ "_id" : 3, "name" : "ahn", "age" : 22, "type" : 2, "status" : "A", "favorites" : { "artist" : "Cassatt", "food" : "cake" }, "finished" : [ 6 ], "badges" : [ "blue", "red" ], "points" : [ { "points" : 81, "bonus" : 8 }, { "points" : 55, "bonus" : 20 } ] }
{ "_id" : 6, "name" : "abc", "age" : 43, "type" : 1, "status" : "A", "favorites" : { "food" : "pizza", "artist" : "Picasso" }, "finished" : [ 18, 12 ], "badges" : [ "black", "blue" ], "points" : [ { "points" : 78, "bonus" : 8 }, { "points" : 57, "bonus" : 7 } ] }
3.2 操作符查詢
mongodb支持使用操作符來構造查詢條件,比如比較操作符,如$gt,$lt等。使用操作符的查詢條件通過 {<field>: {<operator>:<value>}} 來表示。假設我們要查詢age超過22的用戶,可以這么做:
db.users.find({age: {$gt: 22}})
查詢結果
{ "_id" : 2, "name" : "bob", "age" : 42, "type" : 1, "status" : "A", "favorites" : { "artist" : "Miro", "food" : "meringue" }, "finished" : [ 11, 25 ], "badges" : [ "green" ], "points" : [ { "points" : 85, "bonus" : 20 }, { "points" : 64, "bonus" : 12 } ] }
{ "_id" : 4, "name" : "xi", "age" : 34, "type" : 2, "status" : "D", "favorites" : { "artist" : "Chagall", "food" : "chocolate" }, "finished" : [ 5, 11 ], "badges" : [ "red", "black" ], "points" : [ { "points" : 53, "bonus" : 15 }, { "points" : 51, "bonus" : 15 } ] }
{ "_id" : 5, "name" : "xyz", "age" : 23, "type" : 2, "status" : "D", "favorites" : { "artist" : "Noguchi", "food" : "nougat" }, "finished" : [ 14, 6 ], "badges" : [ "orange" ], "points" : [ { "points" : 71, "bonus" : 20 } ] }
{ "_id" : 6, "name" : "abc", "age" : 43, "type" : 1, "status" : "A", "favorites" : { "food" : "pizza", "artist" : "Picasso" }, "finished" : [ 18, 12 ], "badges" : [ "black", "blue" ], "points" : [ { "points" : 78, "bonus" : 8 }, { "points" : 57, "bonus" : 7 } ] }
3.3 and關系
mongodb支持的and關系查詢很簡單,當一個查詢條件中包含多個<field:value>對的時候,這些條件之間的關系就是and關系。所以and關系的查詢可以這樣表示 {<field1>:<value1>, <field2>:<value2>, ...,<fieldN>:<valueN>} 。假設我們要查詢滿足條件:status是'D',并且age大于23的用戶,我們可以這么查詢:
db.users.find({status: 'D', age: {$gt: 23}})
查詢結果
"_id" : 4, "name" : "xi", "age" : 34, "type" : 2, "status" : "D", "favorites" : { "artist" : "Chagall", "food" : "chocolate" }, "finished" : [ 5, 11 ], "badges" : [ "red", "black" ], "points" : [ { "points" : 53, "bonus" : 15 }, { "points" : 51, "bonus" : 15 } ] }
3.4 or關系
mongodb通過操作符"$or"來支持or關系的查詢。or關系的查詢條件可以這么構造: {$or: [{<field1>:<value1>}, {<field2>:<value2>},..., {<fieldN>:<valueN>}]} 。比如我們想查詢status是'A' 或者age大于23的用戶,我們可以這么做:
db.users.find({$or: [{status: 'A'}, {age: {$gt: 23}}]})
查詢條件
{ "_id" : 2, "name" : "bob", "age" : 42, "type" : 1, "status" : "A", "favorites" : { "artist" : "Miro", "food" : "meringue" }, "finished" : [ 11, 25 ], "badges" : [ "green" ], "points" : [ { "points" : 85, "bonus" : 20 }, { "points" : 64, "bonus" : 12 } ] }
{ "_id" : 3, "name" : "ahn", "age" : 22, "type" : 2, "status" : "A", "favorites" : { "artist" : "Cassatt", "food" : "cake" }, "finished" : [ 6 ], "badges" : [ "blue", "red" ], "points" : [ { "points" : 81, "bonus" : 8 }, { "points" : 55, "bonus" : 20 } ] }
{ "_id" : 4, "name" : "xi", "age" : 34, "type" : 2, "status" : "D", "favorites" : { "artist" : "Chagall", "food" : "chocolate" }, "finished" : [ 5, 11 ], "badges" : [ "red", "black" ], "points" : [ { "points" : 53, "bonus" : 15 }, { "points" : 51, "bonus" : 15 } ] }
{ "_id" : 6, "name" : "abc", "age" : 43, "type" : 1, "status" : "A", "favorites" : { "food" : "pizza", "artist" : "Picasso" }, "finished" : [ 18, 12 ], "badges" : [ "black", "blue" ], "points" : [ { "points" : 78, "bonus" : 8 }, { "points" : 57, "bonus" : 7 } ] }
4. 嵌套文檔查詢
如果在文檔中的一個字段上的值也是一個文檔,當我們需要查詢這個文檔中的子文檔中的值得時候,就涉及到嵌套文檔的查詢。MongoDB支持對嵌套文檔的查詢。
4.1 匹配整個子文檔
匹配整個子文檔可以認為也是一種等值查詢,只不過這次的值是一個子文檔。所以查詢條件就是這樣的 {<field>:<sub document>} 。假設我們要查詢favorites這個字段上,artist為'Picasso',food為'pizza'的用戶,我們可以這樣做:
db.users.find( { favorites: { artist: "Picasso", food: "pizza" } } )
查詢結果
{ "_id" : 1, "name" : "sue", "age" : 19, "type" : 1, "status" : "P", "favorites" : { "artist" : "Picasso", "food" : "pizza" }, "finished" : [ 17, 3 ], "badges" : [ "blue", "black" ], "points" : [ { "points" : 85, "bonus" : 20 }, { "points" : 85, "bonus" : 10 } ] }
4.2 匹配子文檔中的字段
mongodb支持匹配子文檔中的字段,通過點(.)符號來表示子文檔中的字段,比如我們在favorites字段對應的子文檔中的artist字段上做查詢操作,可以通過 favorites.artist 來表示這個子文檔中的artist字段
db.users.find( { "favorites.artist": "Picasso" } )
查詢結果
{ "_id" : 1, "name" : "sue", "age" : 19, "type" : 1, "status" : "P", "favorites" : { "artist" : "Picasso", "food" : "pizza" }, "finished" : [ 17, 3 ], "badges" : [ "blue", "black" ], "points" : [ { "points" : 85, "bonus" : 20 }, { "points" : 85, "bonus" : 10 } ] }
{ "_id" : 6, "name" : "abc", "age" : 43, "type" : 1, "status" : "A", "favorites" : { "food" : "pizza", "artist" : "Picasso" }, "finished" : [ 18, 12 ], "badges" : [ "black", "blue" ], "points" : [ { "points" : 78, "bonus" : 8 }, { "points" : 57, "bonus" : 7 } ] }
5. 在數組上查詢
如果文檔中的字段的值是數組類型,mongodb支持對數組類型的字段構造查詢條件。
5.1 匹配整個數組
mongodb對整個數組進行匹配的時候,和匹配整個嵌套文檔的方式類似。只要在條件中給出整個數組就可以了,就像這樣 {<field>:<value>} ,只不過這里的<value>是需要匹配的整個數組。假設我們需要查找badges的值為"['blue', 'black']"的用戶,我們可以這樣做
db.users.find( { badges: [ "blue", "black" ] } )
查詢結果
{ "_id" : 1, "name" : "sue", "age" : 19, "type" : 1, "status" : "P", "favorites" : { "artist" : "Picasso", "food" : "pizza" }, "finished" : [ 17, 3 ], "badges" : [ "blue", "black" ], "points" : [ { "points" : 85, "bonus" : 20 }, { "points" : 85, "bonus" : 10 } ] }
5.2 查找數組中的一個元素
除了對數組類型的字段做完全匹配的查詢,我們也可以把數組的元素作為查詢條件,主要數組中包含了這個元素,那么都會被匹配到。比如我們需要查找badges的數組中包含了'black'元素的所有用戶,我們可以這樣做
db.users.find( { badges: "black" } )
查詢結果
{ "_id" : 1, "name" : "sue", "age" : 19, "type" : 1, "status" : "P", "favorites" : { "artist" : "Picasso", "food" : "pizza" }, "finished" : [ 17, 3 ], "badges" : [ "blue", "black" ], "points" : [ { "points" : 85, "bonus" : 20 }, { "points" : 85, "bonus" : 10 } ] }
{ "_id" : 4, "name" : "xi", "age" : 34, "type" : 2, "status" : "D", "favorites" : { "artist" : "Chagall", "food" : "chocolate" }, "finished" : [ 5, 11 ], "badges" : [ "red", "black" ], "points" : [ { "points" : 53, "bonus" : 15 }, { "points" : 51, "bonus" : 15 } ] }
{ "_id" : 6, "name" : "abc", "age" : 43, "type" : 1, "status" : "A", "favorites" : { "food" : "pizza", "artist" : "Picasso" }, "finished" : [ 18, 12 ], "badges" : [ "black", "blue" ], "points" : [ { "points" : 78, "bonus" : 8 }, { "points" : 57, "bonus" : 7 } ] }
可以看到,這三個用戶的badges字段中的值中,都有‘black’元素在數組中。
5.3 匹配數組中指定下標的元素
mongodb支持把數組中指定下標的元素作為查詢條件來構造查詢語句,通過類似于引用子文檔的點號(.)方式來說引用指定下標的元素。比如badges字段中數組的第一個元素,可以表示成: badges.0 ,類似的,第N個就是 badges.N 。假設我們想查找滿足badges數組中的第一個元素是'black'的用戶,我們可以這樣做:
db.users.find( { "badges.0": "black" } )
查詢結果
{ "_id" : 6, "name" : "abc", "age" : 43, "type" : 1, "status" : "A", "favorites" : { "food" : "pizza", "artist" : "Picasso" }, "finished" : [ 18, 12 ], "badges" : [ "black", "blue" ], "points" : [ { "points" : 78, "bonus" : 8 }, { "points" : 57, "bonus" : 7 } ] }
查詢結果看到,只有一個滿足條件的用戶。雖然別的用戶的badges字段也有'black'字段,但是由于需要查找數組的第一個元素是'black'的用戶,所以只有一個用戶是滿足條件的。
5.4 對數組元素指定多個查詢條件
多個條件之間的and關系
mongodb提供了一個"$elemMatch"操作符,這個操作符的作用是對數組中的元素進行多條件匹配,只要數組中至少一個元素滿足指定的條件,那么就表示匹配成功,也就是說,'$elemMatch'操作符指定的條件之間是"與"的關系。來看例子,假設我們要找到滿足finished字段中的數組元素的值大于15,小于20,我們可以這樣做:
db.users.find( { finished: { $elemMatch: { $gt: 15, $lt: 20 } } } )
查詢結果
{ "_id" : 1, "name" : "sue", "age" : 19, "type" : 1, "status" : "P", "favorites" : { "artist" : "Picasso", "food" : "pizza" }, "finished" : [ 17, 3 ], "badges" : [ "blue", "black" ], "points" : [ { "points" : 85, "bonus" : 20 }, { "points" : 85, "bonus" : 10 } ] }
{ "_id" : 6, "name" : "abc", "age" : 43, "type" : 1, "status" : "A", "favorites" : { "food" : "pizza", "artist" : "Picasso" }, "finished" : [ 18, 12 ], "badges" : [ "black", "blue" ], "points" : [ { "points" : 78, "bonus" : 8 }, { "points" : 57, "bonus" : 7 } ] }
我們可以看到,“$elemMatch”操作符的用法,是用指定的多個條件來匹配數組中的每一個值,只要數組中至少有一個值滿足我們指定的條件,就表示匹配成功。
多條件之間的or關系
mongodb在數組匹配的時候,可以返回滿足指定條件的結果的并集。通俗的講,指定的條件之間是“或”的關系,即只要數組中的任何一個元素滿足多個查詢條件中的任何一個,那么就認為這個文檔被匹配上了。比如,我們如果這樣指定查詢條件
db.users.find( { finished: { $gt: 15, $lt: 20 } } )
我們先來看下查詢的結果
{ "_id" : 1, "name" : "sue", "age" : 19, "type" : 1, "status" : "P", "favorites" : { "artist" : "Picasso", "food" : "pizza" }, "finished" : [ 17, 3 ], "badges" : [ "blue", "black" ], "points" : [ { "points" : 85, "bonus" : 20 }, { "points" : 85, "bonus" : 10 } ] }
{ "_id" : 2, "name" : "bob", "age" : 42, "type" : 1, "status" : "A", "favorites" : { "artist" : "Miro", "food" : "meringue" }, "finished" : [ 11, 25 ], "badges" : [ "green" ], "points" : [ { "points" : 85, "bonus" : 20 }, { "points" : 64, "bonus" : 12 } ] }
{ "_id" : 6, "name" : "abc", "age" : 43, "type" : 1, "status" : "A", "favorites" : { "food" : "pizza", "artist" : "Picasso" }, "finished" : [ 18, 12 ], "badges" : [ "black", "blue" ], "points" : [ { "points" : 78, "bonus" : 8 }, { "points" : 57, "bonus" : 7 } ] }
這個查詢條件和上面的元素匹配的查詢條件相比,查詢的結果我們看到,中間的記錄中,finished的值是[11, 25]的也滿足查詢條件。這是因為 {finished: {$gt: 15, $lt: 20}} 這個條件,表示數組中的任何一個元素,只要滿足大于15或者小于20,都被認為是滿足查詢條件的,指定的條件之間是“或”的關系。而通過"$elemMatch"操作符指定的查詢條件,條件之間的關系是“與”的關系。所以不難理解,值為[11, 25]的那個記錄之所以被匹配,是因為它滿足25是大于條件中的15的,而11是小于條件中的20的,所以自然就滿足條件了。
5.5 數組中包含子文檔的查詢
當數組中包含子文檔的時候,也可以為這些子文檔中的字段構造查詢條件。
使用數組下標定位到具體的子文檔
這種方式的查詢條件,是同時利用數組的下標表示和文檔中字段的點號(.)表示法來指定數組中子文檔中的字段。講的有點繞,我們來看具體的例子。
db.users.find( { 'points.0.points': { $lte: 55 } } )
這條查詢語句的意思,表示我們要查詢points字段中,它包含的數組中下標為0的子文檔中的points字段的值,滿足條件{$lte: 55},也就是這個子文檔中的points字段的值小于等于55。查詢結果如下:
{"_id" : 4, "name" : "xi", "age" : 34, "type" : 2, "status" : "D", "favorites" : { "artist" : "Chagall", "food" : "chocolate" }, "finished" : [ 5, 11 ], "badges" : [ "red", "black" ], "points" : [ { "points" : 53, "bonus" : 15 }, { "points" : 51, "bonus" : 15 } ] }
匹配任何一個滿足條件的子文檔
如果我們省略了數組的下標,那么查詢條件就變成了這樣
db.users.find( { 'points.points': { $lte: 55 } } )
它表示查詢points數組中任何一個子文檔,只要子文檔中的points字段的值滿足條件{$lte: 55}就可以了。
查詢結果:
{ "_id" : 3, "name" : "ahn", "age" : 22, "type" : 2, "status" : "A", "favorites" : { "artist" : "Cassatt", "food" : "cake" }, "finished" : [ 6 ], "badges" : [ "blue", "red" ], "points" : [ { "points" : 81, "bonus" : 8 }, { "points" : 55, "bonus" : 20 } ] }
{ "_id" : 4, "name" : "xi", "age" : 34, "type" : 2, "status" : "D", "favorites" : { "artist" : "Chagall", "food" : "chocolate" }, "finished" : [ 5, 11 ], "badges" : [ "red", "black" ], "points" : [ { "points" : 53, "bonus" : 15 }, { "points" : 51, "bonus" : 15 } ] }
可以看到,查詢結果中包含了所有滿足條件的記錄。
多個條件之間的and關系
利用上面提到的數組的多條件“and”關系匹配的方法,也可以用來為數組中的子文檔指定多個匹配條件。查詢條件也是利用了"$elemMatch"操作符:
db.users.find( { points: { $elemMatch: { points: { $lte: 70 }, bonus: 20 } } } )
可以看到,我們在對points數組中的子文檔指定多個匹配匹配條件的時候,和上面提到的對數組中元素指定多個匹配條件的方式類似。只不過,上面是對整數指定匹配條件,這里是換成了對子文檔指定匹配條件,而且子文檔中的字段可以直接引用,不用采用點(.)號的方式引用。
查詢結果
{ "_id" : 3, "name" : "ahn", "age" : 22, "type" : 2, "status" : "A", "favorites" : { "artist" : "Cassatt", "food" : "cake" }, "finished" : [ 6 ], "badges" : [ "blue", "red" ], "points" : [ { "points" : 81, "bonus" : 8 }, { "points" : 55, "bonus" : 20 } ] }
多個條件之間的or關系
和對數組中元素指定多個or關系的查詢條件一樣,對數組中的子文檔指定多個or關系的查詢條件的語句,在形式上類似。來看具體的例子:
db.users.find( { "points.points": { $lte: 70 }, "points.bonus": 20 } )
這里使用點(.)號來引用數組中的子文檔的字段,其中兩個條件之間是“或”的關系,語句的意思大體是這樣的:查詢滿足points數組中,任何一個子文檔的points字段的值不小于70或者任何一個子文檔的bonus字段的值為20的記錄。查詢結果是這樣的:
{ "_id" : 2, "name" : "bob", "age" : 42, "type" : 1, "status" : "A", "favorites" : { "artist" : "Miro", "food" : "meringue" }, "finished" : [ 11, 25 ], "badges" : [ "green" ], "points" : [ { "points" : 85, "bonus" : 20 }, { "points" : 64, "bonus" : 12 } ] }
{ "_id" : 3, "name" : "ahn", "age" : 22, "type" : 2, "status" : "A", "favorites" : { "artist" : "Cassatt", "food" : "cake" }, "finished" : [ 6 ], "badges" : [ "blue", "red" ], "points" : [ { "points" : 81, "bonus" : 8 }, { "points" : 55, "bonus" : 20 } ] }
如果我們對數組的下標做了指定,那么可以在上面的多個“or”條件之上,再加一個數組元素的位置限定。比如:
db.users.find({'points.0.points': {$gte: 70}, 'points.0.bonus': 8})
這里使用了上面提到的,在數組中指定下標的方式來指定數組中的某一個元素。
查詢結果
{ "_id" : 3, "name" : "ahn", "age" : 22, "type" : 2, "status" : "A", "favorites" : { "artist" : "Cassatt", "food" : "cake" }, "finished" : [ 6 ], "badges" : [ "blue", "red" ], "points" : [ { "points" : 81, "bonus" : 8 }, { "points" : 55, "bonus" : 20 } ] }
{ "_id" : 6, "name" : "abc", "age" : 43, "type" : 1, "status" : "A", "favorites" : { "food" : "pizza", "artist" : "Picasso" }, "finished" : [ 18, 12 ], "badges" : [ "black", "blue" ], "points" : [ { "points" : 78, "bonus" : 8 }, { "points" : 57, "bonus" : 7 } ] }
6. 總結
到這里,我們已經差不多講完了mongo中有關查詢語句的語法。從對簡單值的查詢,到對嵌套子文檔的查詢,再到數組的查詢,最后到數組和子文檔嵌套的復雜查詢。以及如何對多個查詢條件做“or”操作和“and”操作。希望這篇文章對各位有一些幫助吧。
講了那么多,光看沒用,還是要多動手實踐,自己動手去敲一遍代碼才會加深印象,如果能在項目中的業務場景中需要用到這些查詢,那么就再好不過了。因為這樣才會讓這些知識更好地被吸收,不然就會掉入學了忘,忘了學的深淵之中。這其實也是寫博客的好處,學了新的知識,即使不能馬上用到工作中,通過一篇博客來鞏固加深印象,雖然沒在實際項目中使用產生的效果好,也是也是有一定的效果的。
來自:http://www.cnblogs.com/duke2016/p/5992521.html