MongoDB特定類型的查詢語(yǔ)句實(shí)例
MongoDB 在一個(gè)文檔中可以使用多種類型的數(shù)據(jù),其中一些類型在查詢時(shí)會(huì)有特別的行為。
null
null 的行為有一些特別。它可以與自身匹配,所以如果有一個(gè)包含如下文檔的集合:
> var documents = [ ... {_id: 1, y: null}, ... {_id: 2, y: 1}, ... {_id: 3, y: 2} ... ] > db.myCollection.insertMany(documents) { "acknowledged" : true, "insertedIds" : [ 1, 2, 3 ] }
那么可以按照預(yù)期的方式查詢 “y” 鍵為 null 的文檔:
> db.myCollection.find({y: null})
不過(guò),null 同樣會(huì)匹配“不存在”這個(gè)條件。因此,對(duì)一個(gè)鍵進(jìn)行 null 值的請(qǐng)求還會(huì)返回缺少這個(gè)鍵的所有文檔:
> db.myCollection.find({x: null})
如果僅想匹配鍵值為 null 的文檔,則需要檢查該鍵的值是否為 null,并且通過(guò) "$exists"條件確認(rèn)該鍵已存在。
> db.myCollection.find({x: {$eq: null, $exists: true}})
正則表達(dá)式
“$regex” 可以在查詢中為字符串的模式匹配提供正則表達(dá)式功能。正則表達(dá)式對(duì)于靈活的字符串匹配非常有用。如果要查找所有用戶名為 Joe 或 joe 的用戶,那么可以使用正則表達(dá)式進(jìn)行不區(qū)分大小寫的匹配:
> db.users.find({name: {$regex: /joe/i}})
可以在正則表達(dá)式中使用標(biāo)志(如 i),但這沒(méi)有強(qiáng)制要求。如果除了匹配各種大小寫組合形式的“joe”之外,還希望匹配如“joey”這樣的鍵,那么可以改進(jìn)一下剛剛的正則表達(dá)式:
> db.users.find({name: {$regex: /joey?/i}})
MongoDB 會(huì)使用 Perl 兼容的正則表達(dá)式(PCRE)庫(kù)來(lái)對(duì)正則表達(dá)式進(jìn)行匹配。任何PCRE 支持的正則表達(dá)式語(yǔ)法都能被 MongoDB 接受。在查詢中使用正則表達(dá)式之前,最好先在 JavaScript shell 中檢查一下語(yǔ)法,這樣可以確保匹配與預(yù)想的一致。
MongoDB 可以利用索引來(lái)查詢前綴正則表達(dá)式(如 /joey/)。索引不能用于不區(qū)分大小寫的搜索(/joey/i)。當(dāng)正則表達(dá)式以插入符號(hào)(^)或左錨點(diǎn)(\A)開頭時(shí),它就是“前綴表達(dá)式”。如果正則表達(dá)式使用了區(qū)分大小寫的查詢,那么當(dāng)字段存在索引時(shí),則可以對(duì)索引中的值進(jìn)行匹配。如果它也是一個(gè)前綴表達(dá)式,那么可以將搜索限制在由該索引的前綴所形成的范圍內(nèi)的值。
正則表達(dá)式也可以匹配自身。雖然很少有人會(huì)將正則表達(dá)式插入數(shù)據(jù)庫(kù)中,但是如果你這么做了,那么它也可以匹配到自身。
查詢數(shù)組
查詢數(shù)組元素的方式與查詢標(biāo)量值相同。假設(shè)有一個(gè)數(shù)組是水果列表,如下所示:
> db.food.insertOne({fruit: ["apple", "banana", "peach"]}) { "acknowledged" : true, "insertedId" : ObjectId("6358e513cc245bb639adb4d9") }
則下面的查詢可以成功匹配到該文檔:
> db.food.find({fruit: "banana"}).pretty()
這個(gè)查詢就好像對(duì)一個(gè)這樣的(不合法)文檔進(jìn)行查詢:{“fruit” : “apple”, “fruit” :“banana”, “fruit” : “peach”}。
“$all”
如果需要通過(guò)多個(gè)元素來(lái)匹配數(shù)組,那么可以使用 “$all”。這允許你匹配一個(gè)元素列表。假設(shè)我們創(chuàng)建了一個(gè)包含 3 個(gè)元素的集合:
> db.food.insertMany([ ... {_id: 1, fruit: ["apple", "banana", "peach"]}, ... {_id: 2, fruit: ["apple", "kumquat", "orange"]}, ... {_id: 3, fruit: ["cherry", "banana", "apple"]} ... ]) { "acknowledged" : true, "insertedIds" : [ 1, 2, 3 ] } > db.food.find().pretty() { "_id" : 1, "fruit" : [ "apple", "banana", "peach" ] } { "_id" : 2, "fruit" : [ "apple", "kumquat", "orange" ] } { "_id" : 3, "fruit" : [ "cherry", "banana", "apple" ] }
可以使用 “$all” 查詢來(lái)找到同時(shí)包含元素 “apple” 和 “banana” 的文檔:
> db.food.find({fruit: {$all: ["apple", "banana"]}})
這里的順序無(wú)關(guān)緊要。注意,上面第二個(gè)結(jié)果中的 “banana” 在 “apple” 之前。如果在" a l l " 中使用只有一個(gè)元素的數(shù)組,那么這個(gè)效果和不使用 " all" 中使用只有一個(gè)元素的數(shù)組,那么這個(gè)效果和不使用 " all"中使用只有一個(gè)元素的數(shù)組,那么這個(gè)效果和不使用"all" 是一樣的。例如,{fruit : {$all : [‘apple’]} 和 {fruit : ‘apple’} 會(huì)匹配相同的文檔。
也可以使用整個(gè)數(shù)組進(jìn)行精確匹配。不過(guò),精確匹配無(wú)法匹配上元素丟失或多余的文檔。
例如,下面這樣可以匹配之前的第一個(gè)文檔:
> db.food.find({fruit: ["apple", "banana", "peach"]})
但是下面這樣就不行:
> db.food.find({"fruit" : ["apple", "banana"]})
這樣也無(wú)法匹配:
> db.food.find({"fruit" : ["banana", "apple", "peach"]})
如果想在數(shù)組中查詢特定位置的元素,可以使用 key.index 語(yǔ)法來(lái)指定下標(biāo):
> db.food.find({"fruit.2": "peach"})
數(shù)組下標(biāo)都是從 0 開始的,因此這個(gè)語(yǔ)句會(huì)用數(shù)組的第 3 個(gè)元素與字符串 “peach” 進(jìn)行匹配。
“$size”
“$size” 條件運(yùn)算符對(duì)于查詢數(shù)組來(lái)說(shuō)非常有用,可以用它查詢特定長(zhǎng)度的數(shù)組,如下所示。
> db.food.find({fruit: {$size: 3}})
一種常見(jiàn)的查詢是指定一個(gè)長(zhǎng)度范圍。“$size” 并不能與另一個(gè) $ 條件運(yùn)算符(如"$gt")組合使用,但這種查詢可以通過(guò)在文檔中添加一個(gè) “size” 鍵的方式來(lái)實(shí)現(xiàn)。之后每次向指定數(shù)組添加元素時(shí),同時(shí)增加 “size” 的值。如果原本的更新是這樣:
> db.food.update({fruit: {$all: ["apple", "banana"]}}, {$push: {fruit: "strawberry"}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.food.find() { "_id" : 1, "fruit" : [ "apple", "banana", "peach", "strawberry" ] } { "_id" : 2, "fruit" : [ "apple", "kumquat", "orange" ] } { "_id" : 3, "fruit" : [ "cherry", "banana", "apple" ] }
那么可以很容易地轉(zhuǎn)換成這樣:
> db.food.update({fruit: {$all: ["apple", "banana"]}}, ... {$push: {fruit: "strawberry"}, $inc: {size: 1}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
自增操作的速度非???,因此任何性能損失都可以忽略不計(jì)。這樣存儲(chǔ)文檔后就可以執(zhí)行如下查詢:
> db.food.find({size: {$eq: 1}})
很遺憾,這種技巧無(wú)法與 “$addToSet” 運(yùn)算符聯(lián)合使用。
“$slice”
“$slice” 運(yùn)算符可以返回一個(gè)數(shù)組鍵中元素的子集。
假設(shè)現(xiàn)在有一個(gè)關(guān)于博客文章的文檔,我們希望返回前 10 條評(píng)論:
> db.blog.findOne(criteria, {"comments" : {"$slice" : 10}})
同樣,如果想返回后 10 條評(píng)論,則可以使用 -10:
> db.blog.findOne(criteria, {"comments" : {"$slice" : -10}})
“$slice” 也可以指定偏移量和返回的元素?cái)?shù)量來(lái)獲取數(shù)組中間的結(jié)果:
> db.blog.findOne(criteria, {"comments" : {"$slice" : [23, 10]}})
這個(gè)操作會(huì)略過(guò)前 23 個(gè)元素,返回第 24~33 個(gè)元素。如果數(shù)組中的元素少于 33 個(gè),則會(huì)返回盡可能多的元素。
除非特別指定,否則在使用 “$slice” 時(shí)會(huì)返回文檔中的所有鍵。
可以使用 “$slice” 來(lái)獲取最后一條評(píng)論,如下所示:
> db.blog.findOne(criteria, {"comments" : {"$slice" : -1}})
返回一個(gè)匹配的數(shù)組元素
如果知道數(shù)組元素的下標(biāo),那么 “$slice” 非常有用。但有時(shí)我們希望返回與查詢條件匹配的任意數(shù)組元素。這時(shí)可以使用 $ 運(yùn)算符來(lái)返回匹配的元素。對(duì)于前面的博客文章示例,可以這樣獲得 Bob 的評(píng)論:
> db.blog.find({"comments.name": "bob"}, {"comments.$": 1})
注意,這種方式只會(huì)返回每個(gè)文檔中第一個(gè)匹配的元素:如果 Bob 在這篇博客中留下了多條評(píng)論,那么只有 “comments” 數(shù)組中的第一個(gè)會(huì)被返回。
數(shù)組與范圍查詢的相互作用
文檔中的標(biāo)量(非數(shù)組元素)必須與查詢條件中的每一條子句相匹配。如果使用 {“x” :{“ g t " : 10 , " gt" : 10, " gt":10,"lt” : 20}} 進(jìn)行查詢,那么 “x” 必須同時(shí)滿足大于 10 且小于 20。然而,如果文檔中的 “x” 字段是一個(gè)數(shù)組,那么當(dāng) “x” 鍵的某一個(gè)元素與查詢條件的任意一條語(yǔ)句相匹配(查詢條件中的每條語(yǔ)句可以匹配不同的數(shù)組元素)時(shí),此文檔也會(huì)被返回。
理解這種行為最好的方式就是來(lái)看一個(gè)例子。假設(shè)現(xiàn)在有如下幾個(gè)文檔:
{"x" : 5} {"x" : 15} {"x" : 25} {"x" : [5, 25]}
如果想找出 “x” 的值在 10 和 20 之間的所有文檔,那么你可能會(huì)本能地構(gòu)建這樣的查詢,即 db.test.find({“x” : {“ g t " : 10 , " gt" : 10, " gt":10,"lt” : 20}}),然后期望它會(huì)返回一個(gè)文檔:{“x” :15}。然而,當(dāng)實(shí)際運(yùn)行時(shí),我們得到了兩個(gè)文檔,如下所示:
> db.test.find({"x" : {"$gt" : 10, "$lt" : 20}}) {"x" : 15} {"x" : [5, 25]}
5 和 25 都不在 10 和 20 之間,但由于 25 與查詢條件中的第一個(gè)子句(“x” 的值大于10)相匹配,5 與查詢條件中的第二個(gè)子句(“x” 的值小于 20)相匹配,因此這個(gè)文檔會(huì)被返回。
這樣就使得針對(duì)數(shù)組的范圍查詢基本上失去了作用:一個(gè)范圍會(huì)匹配任何多元素?cái)?shù)組。有幾種方法可以獲得預(yù)期的行為。
可以使用 “ e l e m M a t c h " 強(qiáng)制 M o n g o D B 將這兩個(gè)子句與單個(gè)數(shù)組元素進(jìn)行比較。不過(guò),這里有一個(gè)問(wèn)題, " elemMatch" 強(qiáng)制 MongoDB 將這兩個(gè)子句與單個(gè)數(shù)組元素進(jìn)行比較。不過(guò),這里有一個(gè)問(wèn)題," elemMatch"強(qiáng)制MongoDB將這兩個(gè)子句與單個(gè)數(shù)組元素進(jìn)行比較。不過(guò),這里有一個(gè)問(wèn)題,"elemMatch” 不會(huì)匹配非數(shù)組元素:
> db.test.find({"x" : {"$elemMatch" : {"$gt" : 10, "$lt" : 20}}}) > // 沒(méi)有結(jié)果
文檔 {“x” : 15} 不再與查詢條件匹配了,因?yàn)樗?“x” 字段不是一個(gè)數(shù)組。也就是說(shuō),你應(yīng)該有充分的理由在一個(gè)字段中混合數(shù)組和標(biāo)量值,而這在很多場(chǎng)景中并不需要。對(duì)于這樣的情況,“$elemMatch” 為數(shù)組元素的范圍查詢提供了一個(gè)很好的解決方案。
如果在要查詢的字段上有索引,那么可以使用 min 和 max 將查詢條件遍歷的索引范圍限制為 “ g t " 和 " gt" 和 " gt"和"lt” 的值:
> db.test.find({"x" : {"$gt" : 10, "$lt" : 20}}).min({"x" : 10}).max({"x" : 20}) {"x" : 15}
現(xiàn)在,這條查詢語(yǔ)句只會(huì)遍歷值在 10 和 20 之間的索引,不會(huì)與值為 5 和 25 的這兩個(gè)條目進(jìn)行比較。但是,只有在要查詢的字段上存在索引時(shí),才能使用 min 和 max,并且必須將索引的所有字段傳遞給 min 和 max。
在查詢可能包含數(shù)組的文檔的范圍時(shí),使用 min 和 max 通常是一個(gè)好主意。在整個(gè)索引范圍內(nèi)對(duì)數(shù)組使用 “ g t " / " gt"/" gt"/"lt” 進(jìn)行查詢是非常低效的。它基本上接受任何值,因此會(huì)搜索每個(gè)索引項(xiàng),而不僅僅是索引范圍內(nèi)的值。
查詢內(nèi)嵌文檔
查詢內(nèi)嵌文檔的方法有兩種:查詢整個(gè)文檔或針對(duì)其單個(gè)鍵–值對(duì)進(jìn)行查詢。
查詢整個(gè)內(nèi)嵌文檔的工作方式與普通查詢相同。假設(shè)有這樣一個(gè)文檔:
{ "name" : { "first" : "Joe", "last" : "Schmoe" }, "age" : 45 }
可以像下面這樣查詢姓名為 Joe Schmoe 的人:
> db.people.find({"name" : {"first" : "Joe", "last" : "Schmoe"}})
然而,如果要查詢一個(gè)完整的子文檔,這個(gè)子文檔就必須精確匹配。如果 Joe 決定添加一個(gè)代表中間名的字段,這個(gè)查詢就無(wú)法工作了,因?yàn)椴樵儣l件不再與整個(gè)內(nèi)嵌文檔相匹配。而且這種查詢還是與順序相關(guān)的:{“last” : “Schmoe”, “first” : “Joe”} 就無(wú)法匹配。
如果可能,最好只針對(duì)內(nèi)嵌文檔的特定鍵進(jìn)行查詢。這樣,即使數(shù)據(jù)模式變了,也不會(huì)導(dǎo)致所有查詢因?yàn)樾枰_匹配而無(wú)法使用??梢允褂命c(diǎn)表示法對(duì)內(nèi)嵌文檔的鍵進(jìn)行查詢:
> db.people.find({"name.first" : "Joe", "name.last" : "Schmoe"})
這時(shí),如果 Joe 增加了更多的鍵,那么這個(gè)查詢?nèi)匀豢梢云ヅ渌男蘸兔?/p>
這種點(diǎn)表示法是查詢文檔和其他文檔類型的主要區(qū)別。查詢文檔可以包含點(diǎn),表示“進(jìn)入內(nèi)嵌文檔內(nèi)部”的意思。點(diǎn)表示法也是待插入文檔不能包含 . 字符的原因。當(dāng)人們?cè)噲D將URL 保存為鍵時(shí),常常會(huì)遇到這種限制。解決這個(gè)問(wèn)題的一種方法是在插入前或者提取后始終執(zhí)行全局替換,用點(diǎn)字符替換 URL 中不合法的字符。
隨著文檔結(jié)構(gòu)變得越來(lái)越復(fù)雜,內(nèi)嵌文檔的匹配可能會(huì)變得有點(diǎn)兒棘手。假設(shè)我們正在存儲(chǔ)博客文章,要找到 Joe 發(fā)表的 5 分以上的評(píng)論??梢园凑找韵路绞綄?duì)文章進(jìn)行建模:
> db.blog.find() { "content" : "...", "comments" : [ { "author" : "joe", "score" : 3, "comment" : "nice post" }, { "author" : "mary", "score" : 6, "comment" : "terrible post" } ] }
這時(shí),不能直接使用 db.blog.find({“comments” : {“author” : “joe”, “score” : {“KaTeX parse error: Expected 'EOF', got '}' at position 8: gte" :5}?}}) 進(jìn)行查詢。內(nèi)嵌文檔的匹…gte” : 5}})也不行,因?yàn)榉献髡邨l件的評(píng)論與符合分?jǐn)?shù)條件的評(píng)論可能不是同一條。也就是說(shuō),這會(huì)返回上面顯示的那個(gè)文檔:因?yàn)樗ヅ淞说谝粭l評(píng)論中的 “author” : “joe” 和第二條評(píng)論中的 “score” : 6。
要正確指定一組條件而無(wú)須指定每個(gè)鍵,請(qǐng)使用 “$elemMatch”。這種模糊的命名條件允許你在查詢條件中部分指定匹配數(shù)組中的單個(gè)內(nèi)嵌文檔。正確的查詢?nèi)缦滤荆?/p>
> db.blog.find({"comments" : {"$elemMatch" : {"author" : "joe", "score" : {"$gte" : 5}}}})
“$elemMatch” 允許你將限定條件進(jìn)行“分組”。僅當(dāng)需要對(duì)一個(gè)內(nèi)嵌文檔的多個(gè)鍵進(jìn)行操作時(shí)才會(huì)用到它。
總結(jié)
到此這篇關(guān)于MongoDB特定類型的查詢語(yǔ)句的文章就介紹到這了,更多相關(guān)MongoDB特定類型查詢內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mongodb聚合_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了mongodb聚合的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08MongoDB系列教程(四):設(shè)置用戶訪問(wèn)權(quán)限
這篇文章主要介紹了MongoDB系列教程(四):設(shè)置用戶訪問(wèn)權(quán)限,本文講解了在Windows環(huán)境下如何創(chuàng)建用戶認(rèn)證,需要的朋友可以參考下2015-05-05python實(shí)現(xiàn)爬蟲數(shù)據(jù)存到 MongoDB
本文給大家分享的是使用python實(shí)現(xiàn)將爬蟲爬到的數(shù)據(jù)存儲(chǔ)到mongoDB數(shù)據(jù)庫(kù)中的實(shí)例代碼,有需要的小伙伴可以參考下2016-09-09關(guān)于MongoDB數(shù)據(jù)庫(kù)學(xué)習(xí)路線指南
這篇文章主要介紹了關(guān)于MongoDB數(shù)據(jù)庫(kù)學(xué)習(xí)路線指南,給大家以學(xué)習(xí)路線地圖的形式講解該怎么學(xué)習(xí)MongoDB數(shù)據(jù)庫(kù),需要的朋友可以參考下2023-04-04Mongodb基本操作與Python連接mongodb并進(jìn)行基礎(chǔ)操作的方法
mongodb是基于分布式文件存儲(chǔ)的nosql(非關(guān)系型)數(shù)據(jù)庫(kù),本文分享了mongodb的基礎(chǔ)操作和Python連接并操作mongodb的基礎(chǔ)方法,基礎(chǔ)的不能再基礎(chǔ)了2018-09-09mongodb安裝_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了mongodb安裝,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08mongodb 集群重構(gòu)和釋放磁盤空間實(shí)例詳解
這篇文章主要介紹了mongodb 集群重構(gòu)和釋放磁盤空間實(shí)例詳解的相關(guān)資料,具有一定的參考價(jià)值,需要的朋友可以參考下2016-11-11