2016-02-12 56 views
4

mongo $和選擇器是如何工作的?我無法獲得正確的結果。

比方說,我有一個集合是這樣的:

{ "_id" : "F7mdaZC2eBQDXA5wx", "quantity" : 5 } 
{ "_id" : "F7mdaZC2eBQDXA5wx", "quantity" : 9 } 
{ "_id" : "F7mdaZC2eBQDXA5wx", "quantity" : 34 } 
{ "_id" : "F7mdaZC2eBQDXA5wx", "quantity" : 66 } 

和我運行查詢:

var selectorMin = 9; 
var selectorMax = 42; 

ScrapReport.find({ $and: [ { quantity: { $gte: selectorMin }, quantity: { $lte: selectorMax } } ] }) 

我希望蒙戈返回我只有9和34,但由於某種原因,也返回5和66.

我的查詢出了什麼問題?

回答

4

您的查詢返回的所有文檔樣本中,因爲它是第一個尋找的文件,其quantity >= 9即9,34和66 結合了其文件quantity <= 42即34,9和5這不是尋找一個查詢在特定範圍內的文件,但您的查詢明確將查找satisify兩個範圍,即

Documents which satisfy "quantity >= 9" 
+ 
Documents which satisfy "quantity <= 42" 

Documents which satisfy "9 <= quantity <= 42" 

只是SIM卡的所有文件plify查詢到

ScrapReport.find({ "quantity": { "$gte": selectorMin, "$lte": selectorMax } }) 

這樣,你指定一個範圍MongoDB的您的文檔與即

9 <= quantity <= 42 

指定用逗號分隔的表達式列表進行過濾,意味着一個隱含的與運算,使用一個明確的,與當運算符相同的字段或運算符必須在多個表達式中指定時,運算符爲$and

+0

我確實嘗試過,但它仍然返回我與$和 相同的結果編輯:對不起,我看到了現在的差異,正確的答案。 – Villemh

+2

這個描述的問題就好像是使用$或'來代替'$和'。查看@ umesh對OP真正問題的回答。 – JohnnyHK

1

其實你在那裏有兩個問題:因爲重複鍵允許

ScrapReport.find({ "quantity": { "$lte": selectorMax } }) 

的原因是:

你的查詢等效於以下內容:

ScrapReport.find({ "$and": [{ "quantity": { "$lte": selectorMax } } ] }) 

,甚至更好在JSON文檔中,但給定鍵的最後一個值被保留。

因此,這將只返回「數量」小於或等於selectorMax的所有文檔。

第二個問題在@ chridam的答案已經被提到如此正確的查詢是:

ScrapReport.find({ "quantity": { "$gte": selectorMin, "$lte": selectorMax } }) 
3

使用類似建議將工作其他答案含蓄蘊藉的操作。但我想更深入地瞭解具體情況。 爲什麼您的查詢無法按預期工作?

爲什麼?爲什麼這個貌似正確查詢你的返回不正確的結果?畢竟,無論您使用隱式還是顯式AND操作都應該是您的選擇的問題,無論您使用哪種表單,您都應該能夠實現目標。 如何使您的查詢與顯式AND操作一起工作?

讓我們看看AND操作的語法。

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

AND運算符的值應該是一個包含要執行AND操作的表達式的數組。

第一次看到你的查詢後,一切都看起來很好。但是,如果您花一點時間仔細觀察,則會發現查詢與AND語法完全不匹配。它在語法上仍然是正確的。毫無疑問。但這在邏輯上是不正確的。我將解釋如何。

這是您的$and運營商價值

{ $and: [ { quantity: { $gte: selectorMin }, quantity: { $lte: selectorMax } } ] } 

你認爲你有一個表達式quantity: { $gte: selectorMin }和表達式2 quantity: { $lte: selectorMax }。與這些表達式的AND操作應返回數量爲9和34的文檔。但實際上,您擁有的全部是一個表達式。密切關注大括號。您已將這兩個表達式添加到單個{}區塊中。你看到了嗎?實際上,AND運算符沒有第二個表達式。但AND運算符需要兩個或更多表達式才能正常工作。

所以你的查詢語句的形式

{ $and: [ { <expression1> } ] } 

用不正確的形式,結果也將是不正確的。使用正確的查詢的明確,操作

ScrapReport.find({ $and: [ { quantity: { $gte: selectorMin } }, { quantity: { $lte: selectorMax } } ] }) 

你看到區別?試試這個查詢,你將首先得到你期望的結果。

如果您對答案不滿意並且很想知道Mongo如何解釋您的第一個查詢,請進一步閱讀。

考慮這個查詢

ScrapReport.find({ quantity: 9 }) 

,你會想到什麼結果呢?如果您希望Mongo返回數量字段中的值爲9的單個文檔,那麼您是對的。這正是結果。現在考慮具有小扭曲的相同查詢。

ScrapReport.find({ quantity: 9, quantity: 5 }) 

現在的結果是什麼?現在事情變得有趣了吧?如果您執行此查詢並查看結果,您仍然只能看到單個文檔。但是數量字段中的值是5.現在很有趣!

ScrapReport.find({ quantity: 9, quantity: 5, quantity: 34 }) 

這是怎麼回事?結果仍然是數量字段中值爲34的單個文檔。您可以嘗試其他組合。什麼,你會發現這是 -

內的表達式,如果你引用一個場多次,結果將通過最後一個引用該字段在表達式中確定。

現在將這個概念應用到您的原始查詢。已經指出,你有一個單個表達式,其中有兩部分quantity: { $gte: selectorMin }quantity: { $lte: selectorMax }。由於在一個表達式中,你指的是同一個字段兩次,只有最後一個是相關的。選擇標準將是quantity: { $lte: selectorMax }。結果將是數量值分別爲5,9和34的3份文件。

如果您更換訂單,即先寫入quantity: { $lte: selectorMax },然後再寫入quantity: { $gte: selectorMin },則選擇標準將由quantity: { $gte: selectorMin }決定。其結果將是3號文件與數量值9,34和66

雖然這不是你的本意,你原來的查詢是有效

ScrapReport.find({ quantity: { $gte: selectorMin }, quantity: { $lte: selectorMax } }) 

當你錯過括號或在錯誤的位置添加它們,它可以完全改變你的查詢的含義。

道德 - 密切關注您將括號放在複雜查詢中的位置。