2017-07-20 109 views
1

如下片段展示三個查詢:查詢由字段值,在字段陣列不值

  • 找到所有的文件
  • 發現包含含有任一字符串"x"或含有該陣列的字段a的文件串"x"
  • 發現包含含有包含字符串"x"
0陣列的字段 a的文件

我無法找到包含字段a的文檔,其中包含字符串"x",不在數組內。

> db.stuff.find({},{_id:0}) 
{ "a" : "x" } 
{ "a" : [ "x" ] } 
> db.stuff.find({a:"x"},{_id:0}) 
{ "a" : "x" } 
{ "a" : [ "x" ] } 
> db.stuff.find({a:{$elemMatch:{$eq:"x"}}},{_id:0}) 
{ "a" : [ "x" ] } 
> 

回答

1

對於「給定路徑」中的數據實際上是否在數組中,MongoDB基本上不在乎。如果你想的區別,那麼你需要「告訴它」:

db.stuff.find({ "a": "x", "$where": "return !Array.isArray(this.a)" }) 

這是$where增加了討價還價,在那裏你可以提供明確提出了一個條件:「這是一個數組」通過Array.isArray()在JavaScript評估中。而JavaScript NOT !聲明顛倒了邏輯。

另一種方法是添加$exists檢查:

db.stuff.find({ "a": "x", "a.0": { "$exists": false } }) 

其中也基本上問「這是一個數組」通過尋找該第一元素索引。所以「反向」false大小寫意味着「這不是一個數組」。

或者即使你注意,您可以使用$elemMatch只選擇陣列,但「否定」,使用$not

db.stuff.find({ "a": { "$not": { "$elemMatch": { "$eq": "x" } } } }) 

雖然可能「而不是」最好的選擇,因爲這也是「否定索引的使用「,其他例子都通過至少包括」一個「匹配的積極條件來努力避免。因此,它是最好的,包括了「隱AND」組合參數:

db.stuff.find({ 
    "a": { "$eq": "x", "$not": { "$elemMatch": { "$eq": "x" } } } 
}) 

或爲「聚合」不支持$where,您可以測試使用$isArray匯聚運營商應該將MongoDB的版本(3.2或更高版本)支持它:

db.stuff.aggregate([ 
    { "$match": { "a": "x" } }, 
    { "$redact": { 
    "$cond": { 
     "if": { "$not": { "$isArray": "$a" } }, 
     "then": "$$KEEP", 
     "else": "$$PRUNE" 
    } 
    }} 
]) 

注意到在任何可能的情況下以及在任何情況下都提供「常規」查詢條件是一種很好的做法。

還注意到查詢BSON $type通常不會在這種情況下工作,因爲該數組本身的「內容」其實都是「字符串」,這是什麼$type操作是要考慮的,並因此不報告這樣的數組實際上是一個數組。

+0

謝謝!我認爲應該在可能的情況下使用'a.0'的答案,因爲它會使用索引(如果存在),而'$ where'不能。而且,'return'關鍵字沒用。 – stenci

+0

@stenci這不是「無用的」,它只是「$ where」認爲它是「隱含的」,但「良好的語言習慣」(我習慣於這樣做)實際上表明你「應該」實際上總是返回'從任何功能。請注意,即使在這種形式下,'function()'也基本上是「隱含的」。 –