本文將介紹操做符的使用,配合操做符,咱們能夠執行更加複雜的操做。javascript
db.collection.find() 查詢集合中文檔並返回結果爲遊標的文檔集合。html
語法:db.collection.find(query, projection)
參數 類型 描述
query 文檔 可選. 使用查詢操做符指定查詢條件
projection 文檔 可選.使用投影操做符指定返回的鍵。查詢時返回文檔中全部鍵值, 只需省略該參數便可(默認省略).
返回值: 匹配查詢條件的文檔集合的遊標. 若是指定投影參數,查詢出的文檔返回指定的鍵 ,"_id"鍵也能夠從集合中移除掉。
注意:在mongo shell中咱們不須要JavaScript遊標處理方法就能夠直接訪問做爲查詢結果的文檔集合。mongo shell默認返回遊標中的前20條文檔。當執行查詢操做時,mongo shell直接自動的對遊標執行迭代操做並顯示前20條文檔。輸入"it"顯示接下來的20條文檔。
find的第一個參數是查詢條件,其形式也是一個文檔,決定了要返回哪些文檔,空的査詢文檔{}會匹配集合的所有內容。要是不指定査詢文檔,默認就是{},如同SQL中"SELECT * FROM TABLENAME"語句。java
//將返回集合中全部文檔 db.collection.find() //或者 db.collection.find({})
第一個參數若爲鍵/值對時,查詢過程當中就意味着執行了條件篩選,就如同咱們使用Linq查詢數據庫同樣。下面查詢操做將返回user集合中age鍵值爲16的文檔集合。ajax
//mongo db db.user.find({age:16}) //Linq to sql dbContext.user.select(p=>p.age==16)
上面的查詢默認執行「==」操做(就如同linq中 p.age==16),文檔中若存在相同鍵的值和查詢文檔中鍵的值相等的話,就會返回該文檔。正則表達式
第一個參數若包含多個鍵/值對(逗號分隔),則至關於查詢AND組合條件,「條件1 AND條件2 AND…AND 條件N".例如查詢年齡爲28且性別爲男性的文檔集合:sql
//mongo db db.user.find({age:28,sex:"male"}) //Linq to sql dbContext.user.select(p=>p.age==28&&p.sex=="male") //SQL SELECT * FROM user WHERE age=28 AND sex="male"
指定返回的鍵mongodb
咱們能夠經過find 的第二個參數來指定返回的鍵。shell
若find不指定第二個參數,查詢操做默認返回查詢文檔中全部鍵值。像SQL中咱們能夠指定查詢返回字段同樣 ,mongo中也能夠指定返回的鍵,這樣咱們就能夠避免查詢無用鍵值查詢所消耗的資源、會節省傳輸的數據量和內存消耗。數據庫
集合user包含 _id,name,age,sex,email等鍵,若是查詢結果想只顯示集合中的"name"和"age"鍵,可使用以下查詢返回這些鍵,。express
> db.users.find({}, {"name" : 1, "age" : 1})
上面查詢結果中,"_id"這個鍵老是被返回,即使是沒有指定也同樣。可是咱們能夠顯示的將其從查詢結果中移除掉。
> db.users.find({}, {"name" : 1, "age" : 1, "_id":0})
在第二個參數中,指定鍵名且值爲1或者true則是查詢結果中顯示的鍵;若值爲0或者false,則爲不顯示鍵。文檔中的鍵若在參數中沒有指定,查詢結果中將不會顯示(_id例外)。這樣咱們就能夠靈活顯示聲明來指定返回的鍵。
咱們在使用RDMS時,有時會對錶中多個字段之間進行比較。如表store中,有銷售數量soldnum和庫存數量stocknum兩個字段,咱們要查詢表中銷售數量等於庫存數量的記錄時可使用下面的sql語句:
SELECT * FROM store WHERE soldnum=stocknum
那麼換成mongodb呢,使用find()能實現相似的功能嗎?
> db.store.find ({ "soldnum" : "stocknum"}) //或者 > db.store.find ({ "stocknum":"soldnum" })
結果是不行的!!咱們可使用$where運算符來進行相應的操做。
查詢文檔有兩種方式,一種是徹底匹查詢,另外一種是針對鍵/值對查詢。
> db.profile.find() { "_id" : ObjectId("51d7b0d436332e1a5f7299d6"), "name" : { "first" : Barack", "last" : "Obama" } }
>
內嵌文檔的徹底匹配查詢和數組的徹底匹配查詢同樣,內嵌文檔內鍵值對的數量,順序都必須一致纔會匹配:
> db.profile.find({ name : { first : "Barack", last : "Obama" } }); { "_id" : ObjectId("51d7b0d436332e1a5f7299d6"), "name" : { "first" : Barack", "last" : "Obama" } }
>
//無任何返回值 > db.profile.find({ name : { last : "Obama" , first : "Barack"} });
>
推薦採用針對鍵/值對查詢,經過點表示法來精確表示內嵌文檔的鍵:
//查詢結果同樣 db.profile.find({ "name.first" : "Barack" , "name.last" : "Obama"}); //或者 db.profile.find({ "name.last" : "Obama" , "name.first" : "Barack"} );
運行結果:
査詢文檔能夠包含點,來表達「深刻內嵌文檔內部」的意思,點表示法也是待插入的文檔不能包含的緣由。當內嵌文檔變得複雜後,如鍵的值爲內嵌文檔的數組,內嵌文檔的匹配須要些許技巧,例如使用$elemMatch操做符。
集合blogs有以下文檔:
{ "content" : ".....", "comment" : [ { "author" : "zhangsan", "score" : 3, "comment" : "shafa!" }, { "author" : "lisi", "score" : 5, "comment" : "lzsb!" } ] }
咱們想查詢評論中用戶「zhangsan」是否有評分超過4分的評論內容,但咱們利用「點表示法」直接寫是有問題的,這條查詢條件和數組中不一樣的文檔進行了匹配!
> db.blogs.find({"comment.author":"zhangsan", "comment.score":{"$gte":4}});
上面的結果不是咱們指望的,下面使用「$elemMatch」操做符便可將一組條件限定到數組中單條文檔的匹配上:
> db.blogs.find({"comment":{"$elemMatch":{"author":"zhangsan","score":{"$gt":4}}}}); > db.blogs.find({"comment":{"$elemMatch":{"author":"zhangsan","score":{"$gt":2}}}});
下面咱們將配合查詢操做符來執行復雜的查詢操做,好比元素查詢、 邏輯查詢 、比較查詢操做。
咱們使用下面的比較操做符"$gt" 、"$gte"、 "$lt"、 "$lte"(分別對應">"、 ">=" 、"<" 、"<="),組合起來進行範圍的查找。例如查詢年齡爲16-18歲(包含16但不含18)的用戶:
>db.user.find( { age: { $gte: 16 ,$lt:18} }
咱們可使用"$ne"來進行"不相等"操做。例如查詢年齡不爲18歲的用戶:
>db.user.find( { age: {$ne:18} }
精確匹配日期要精確到毫秒,然而咱們一般只是想獲得關於一天、一週或者是一個月的數據,咱們可使用"gt"、"lt"進行範圍査詢。例如,要査找在1990年1月1日出生的用戶:
> start = new Date("1990/01/01") > db.users.find({"birthday" : {"$lt" : start}})
如何檢索出sex鍵值爲null的文檔,咱們使用"in"、"where"操做符,"$in"判斷鍵值是否爲null,"$exists"斷定集合中文檔是否包含該鍵。
//集合中有一條sex鍵值爲null的文檔 {"name":"xiaoming","age":20,"sex":"male"} {"name":"xiaohong","age":22,"sex":"female"} {"name":"lilei","age":24,"sex":null} //返回文檔中存在sex鍵,且值爲null的文檔 db.users.find({sex:{$in:[null],$exists:true }}) //返回文檔中存在birthday鍵,且值爲null的文檔 //文檔沒有birthday鍵,因此結果爲空 db.users.find({birthday:{$in:[null],$exists:true }})
運行截圖:
咱們也能夠運行以下語句:
> db.users.find({sex:null})
查詢結果跟語句"db.users.find({sex:{in:[null],exists:true }})"同樣
可是當爲咱們運行下面語句時,發現查詢結果跟語句"db.users.find({birthday:{in:[null],exists:true }})"不同!
> db.users.find({birthday:null})
查詢返回了全部的文檔!
由於null不只僅匹配自身,並且匹配鍵「不存在的」文檔,集合衆文檔都不存在"birthday"鍵,都匹配查詢條件,因此上面的語句會返回全部的文檔!
咱們最好使用db.users.find({sex:{in:[null],exists:true }})這種格式。
下面先向集合inventory插入3條數據(下面的演示基於此數據),文檔內容以下:
{"name":"t1","amount":16,"tags":[ "school", "book", "bag", "headphone", "appliances" ]}
{"name":"t2","amount":50,"tags":[ "appliances", "school", "book" ]}
{"name":"t3","amount":58,"tags":[ "bag", "school", "book" ]}
匹配那些指定鍵的鍵值中包含數組,並且該數組包含條件指定數組的全部元素的文檔,數組中元素順序不影響查詢結果。
語法: { field: { $all: [ <value> , <value1> ... ] }
查詢出在集合inventory中 tags鍵值包含數組,且該數組中包含appliances、school、 book元素的全部文檔:
db.inventory.find( { tags: { $all: [ "appliances", "school", "book" ] } } )
該查詢將匹配tags鍵值包含以下任意數組的全部文檔:
[ "school", "book", "bag", "headphone", "appliances" ] [ "appliances", "school", "book" ]
查詢結果:
文檔中鍵值類型不是數組,也可使用$all操做符進行查詢操做,以下例所示"$all"對應的數組只有一個值,那麼和直接匹配這個值效果是同樣的。
//查詢結果是相同的,匹配amount鍵值等於50的文檔 db.inventory.find( { amount: {$all:[50]}} ) db.inventory.find( { amount: 50}} )
要是想查詢數組指定位置的元素,則需使用key.index語法指定下標,例以下面查詢出tags鍵值數組中第2個元素爲"school"的文檔:
> db.inventory.find({"tags.1":"school"})
語法:{field: {$size: value} }
查詢集合中tags鍵值包含有3個元素的數組的全部文檔:
> db.inventory.find({tags:{$size:3}})
文檔"{"name":"t1","amount":16,"tags":[ "school", "book", "bag", "headphone", "appliances" ]}",tags鍵值數組包含四個元素,因此不匹配查詢條件。查詢結果:
size必須制定一個定值,不能接受一個範圍值,不能與其他查詢子句組合(比如"gt")。但有時查詢需求就是須要一個長度範圍,這種狀況建立一個計數器字段,當你增長元素的同時增長計數器字段值。
//每一次向指定數組添加元素的時候,"count"鍵值增長1(充當計數功能) db.collection.update({ $push : {field: value}, $inc :{count : 1}}) //比較count鍵值實現範圍查詢 db.collection.find({count : {$gt:2}})
語法: { field: { $in: [<value1>, <value2>, ... <valueN> ] } }
匹配鍵不存在或者鍵值不等於指定數組的任意值的文檔。相似sql中not in(SQL中字段不存在使用會有語法錯誤).
語法: { field: { $nin: [ <value1>, <value2> ... <valueN> ]} }
查詢出amount鍵值爲16或者50的文檔:
db.inventory.find( { amount: { $in: [ 16, 50 ] } } )
//查詢出amount鍵值不爲16或者50的文檔 db.inventory.find( { amount: { $nin: [ 16, 50 ] } } ) //查詢出qty鍵值不爲16或50的文檔,因爲文檔中都不存在鍵qty,因此返回全部文檔 db.inventory.find( { qty: { $nin: [ 16, 50 ] } } )
文檔中鍵值類型不是數組,也可使用$all操做符進行查詢操做,以下例所示"$in"對應的數組只有一個值,那麼和直接匹配這個值效果是同樣的。
//查詢結果是相同的,匹配amount鍵值等於50的文檔 db.inventory.find( { amount: {$in:[50]}} ) db.inventory.find( { amount: 50}} )
指定一個至少包含兩個表達式的數組,選擇出知足該數組中全部表達式的文檔。$and操做符使用短路操做,若第一個表達式的值爲「false」,餘下的表達式將不會執行。
語法: { $and: [ { <expression1> }, { <expression2> } , ... , { <expressionN> } ] }
查詢name鍵值爲「t1」,amount鍵值小於50的文檔:
db.inventory.find({ $and: [ { name: "t1" }, { amount: { $lt:50 } } ] } )
對於下面使用逗號分隔符的表達式列表,MongoDB會提供一個隱式的$and操做:
//等同於{ $and: [ { name: "t1" }, { amount: { $lt:50 } } ] } db.inventory.find({ name: "t1" , amount: { $lt:50 }} )
執行邏輯NOR運算,指定一個至少包含兩個表達式的數組,選擇出都不知足該數組中全部表達式的文檔。
語法: { $nor: [ { <expression1> }, { <expression2> }, ... { <expressionN> } ] }
查詢name鍵值不爲「t1」,amount鍵值不小於50的文檔:
db.inventory.find( { $nor: [ { name: "t1" }, { qty: { $lt: 50 } } ] } )
如果文檔中不存在表達式中指定的鍵,表達式值爲false; false nor false 等於 true,因此查詢結果返回集合中全部文檔:
db.inventory.find( { $nor: [ { sale: true }, { qty: { $lt: 50 } } ] } )
執行邏輯NOT運算,選擇出不能匹配表達式的文檔 ,包括沒有指定鍵的文檔。$not操做符不能獨立使用,必須跟其餘操做一塊兒使用(除$regex)。
語法: { field: { $not: { <operator-expression> } } }
查詢amount鍵值不大於50(即小於等於50)的文檔數據
db.inventory.find( { amount: { $not: { $gt: 50 } } } ) //等同於db.inventory.find( { amount: { $lte: 50 } } )
查詢條件中的鍵gty,文檔中都不存在沒法匹配表示,因此返回集合全部文檔數據。
db.inventory.find( { gty: { $not: { $gt: 50 } } } )
執行邏輯OR運算,指定一個至少包含兩個表達式的數組,選擇出至少知足數組中一條表達式的文檔。
語法: { $or: [ { <expression1> }, { <expression2> }, ... , { <expressionN> } ] }
查詢集合中amount的鍵值大於50或者name的鍵值爲「t1」的文檔:
db.inventory.find( { $or: [ { amount: { $gt: 50 } }, { name: "t1" } ] } )
若是$exists的值爲true,選擇存在該字段的文檔;若值爲false則選擇不包含該字段的文檔(咱們上面在查詢鍵值爲null的文檔時使用"$exists"斷定集合中文檔是否包含該鍵)。
語法: { field: { $exists: <boolean> } }
//查詢不存在qty字段的文檔(全部文檔) db.inventory.find( { qty: { $exists: false } }) //查詢amount字段存在,且值不等於16和58的文檔 db.inventory.find( { amount: { $exists: true, $nin: [ 16, 58 ] } } )
若是該字段的值爲null,$exists的值爲true會返回該條文檔,false則不返回。
//向集合中插入一條amount鍵值爲null的文檔 {"name":"t4","amount":null,"tags":[ "bag", "school", "book" ]} //0條數據 db.inventory.find( { amount: { $exists: false } } ) //全部的數據 db.inventory.find( { amount: { $exists: true } } )
匹配字段值對(divisor)取模,值等於(remainder)的文檔。
語法: { field: { $mod: [ divisor, remainder ]} }
查詢集合中 amount 鍵值爲 4 的 0 次模數的全部文檔,例如 amount 值等於 16 的文檔
db.inventory.find( { amount: { $mod: [ 4, 0 ] } } )
有些狀況下(特殊狀況鍵值爲null時),咱們可使用mod操做符替代使用求模表達式的where操做符,由於後者代價昂貴。
db.inventory.find( { $where: "this.amount % 4 == 0" } )
注意:返回結果怎麼不同。由於有一條文檔的amount鍵值爲null,javascript中null進行數值轉換,會返回"0"。因此該條文檔匹配where操做符求模式了表達式。當文檔中字段值不存在null,就可以使用mod替代$where的表達式.
操做符查詢中能夠對字符串的執行正則匹配。 MongoDB使用Perl兼容的正則表達式(PCRE)庫來匹配正則表達式.
咱們可使用正則表達式對象或者$regex操做符來執行正則匹配:
//查詢name鍵值以「4」結尾的文檔 db.inventory.find( { name: /.4/i } ); db.inventory.find( { name: { $regex: '.4', $options: 'i' } } );
options(使用regex )
注:JavaScript只提供了i和m選項,x和s選項必須使用$regex操做符。
操做符功能強大並且靈活,他可使用任意的JavaScript做爲查詢的一部分,包含JavaScript表達式的字符串或者JavaScript函數。
新建fruit集合並插入以下文檔:
//插入兩條數據 db.fruit.insert({"apple":1, "banana": 4, "peach" : 4}) db.fruit.insert({"apple":3, "banana": 3, "peach" : 4})
比較文檔中的兩個鍵的值是否相等.例如查找出banana等於peach鍵值的文檔(4種方法):
//JavaScrip字符串形式 db.fruit.find( { $where: "this.banana == this.peach" } ) db.fruit.find( { $where: "obj.banana == obj.peach" } )
//JavaScript函數形式 db.fruit.find( { $where: function() { return (this.banana == this.peach) } } ) db.fruit.find( { $where: function() { return obj.banana == obj.peach; } } )
查出文檔中存在的兩個鍵的值相同的文檔,JavaScript函數會遍歷集合中的文檔:
>db.fruit.find({$where:function () { for (var current in this) { for (var other in this) { if (current != other && this[current] == this[other]) { return true; } } } return false; }});
注意:咱們儘可能避免使用"Where"査詢,因爲它們在速度上要比常規査詢慢很多。每個文檔都要從BSON轉換成JavaScript對象,然後通過"where"的表達式來運行;一樣還不能利用索引。
"$slice (projection)"
$slice操做符控制查詢返回的數組中元素的個數。
語法:db.collection.find( { field: value }, { array: {$slice: count } } );
此操做符根據參數"{ field: value }" 指定鍵名和鍵值選擇出文檔集合,而且該文檔集合中指定"array"鍵將返回從指定數量的元素。若是count的值大於數組中元素的數量,該查詢返回數組中的全部元素的。
$slice接受多種格式的參數 包含負數和數組:
//選擇comments的數組鍵值中前五個元素。 db.posts.find( {}, { comments: { $slice: 5 } } ); //選擇comments的數組鍵值中後五個元素。 db.posts.find( {}, { comments: { $slice: -5 } } );
下面介紹指定一個數組做爲參數。數組參數使用[ skip , limit ] 格式,其中第一個值表示在數組中跳過的項目數,第二個值表示返回的項目數。
//選擇comments的數組鍵值中跳過前20項以後前10項元素 db.posts.find( {}, { comments: { $slice: [ 20, 10 ] } } ); //選擇comments的數組鍵值中倒數第20項起前10項元素 db.posts.find( {}, { comments: { $slice: [ -20, 10 ] } } );
"$elemMatch(projection)"
elemMatch投影操做符將限制查詢返回的數組字段的內容只包含匹配elemMatch條件的數組元素。
注意:
假設集合school有以下數據:
{ _id: 1, zipcode: 63109, students: [ { name: "john", school: 102, age: 10 }, { name: "jess", school: 102, age: 11 }, { name: "jeff", school: 108, age: 15 } ] } { _id: 2, zipcode: 63110, students: [ { name: "ajax", school: 100, age: 7 }, { name: "achilles", school: 100, age: 8 }, ] } { _id: 3, zipcode: 63109, students: [ { name: "ajax", school: 100, age: 7 }, { name: "achilles", school: 100, age: 8 }, ] } { _id: 4, zipcode: 63109, students: [ { name: "barney", school: 102, age: 7 }, ] }
下面的操做將查詢郵政編碼鍵值是63109的全部文檔。 $elemMatch操做符將返回 students數組中的第一個匹配條件(內嵌文檔的school鍵且值爲102)的元素。
db.school.find( { zipcode: 63109 },{ students: { $elemMatch: { school: 102 } } } );
查詢結果:
_id爲1的文檔,students數組包含多個元素中存在school鍵且值爲102的元素,$elemMatch只返回一個匹配條件的元素。
_id爲3中的文檔,由於students數組中元素沒法匹配$elemMatch條件,因此查詢結果不包含"students"字段。
$elemMatch能夠指定多個字段的限定條件,下面的操做將查詢郵政編碼鍵值是63109的全部文檔。 $elemMatch操做符將返回 students數組中的第一個匹配條件(內嵌文檔的school鍵且值爲102且age鍵值大於10)的元素。
db.school.find( { zipcode: 63109 },{ students: { $elemMatch: { school: 102, age: { $gt: 10} } } } );
_id等於3 和4的文檔,由於students數組中沒有元素匹配的$elemMatch條件,查詢結果不包含「 students」字段。