2013-07-27 90 views
0

我有以下文檔的集合:

{ 
"_id" : ObjectId("51f1fd2b8188d3117c6da352"), 
"cust_id" : "abc1234", 
"ord_date" : ISODate("2012-10-03T18:30:00Z"), 
"status" : "A", 
"price" : 27, 
"items" : [{ 
    "sku" : "mmm", 
    "qty" : 5, 
    "price" : 2.5 
}, { 
    "sku" : "nnn", 
    "qty" : 5, 
    "price" : 2.5 
}] 
} 

我想用「$其中」中的「項目」的字段,因此東西這樣的:

{$where:"this.items.sku==mmm"} 

我該怎麼辦?它在字段不是數組類型時有效。

回答

0

您在將this.items.sku與變量mmm進行比較,該變量未初始化,因此其值爲unefined。你想要做的是迭代數組,並將每個條目與字符串'mmm'進行比較。這個例子做到這一點通過使用陣列方法some返回true,當傳遞函數的條目中的至少一個返回true

{$where:"return this.items.some(function(entry){return entry.sku =='mmm'})"} 

但實際上,不這樣做。 JohnnyHK在回答評論時說:「我的服務只是用戶和mongodb之間的接口,完全不知道現場客戶想要存儲什麼」。你並沒有真正解釋你的用例,但我相信你可以更好地解決這個問題。

  • ,其中運營商調用,即使這 瑣碎的表達可以與正常的查詢來完成的Javascript引擎的$。這意味着不必要的性能開銷
  • 集合中的每一個文檔都被傳遞給函數,所以當你有索引時,它就不能被使用。
  • 當從客戶端提供的東西中生成JavaScript函數時,您必須小心地正確地轉義和正確地轉義它,否則您的應用程序易受代碼注入的影響。
+0

@Phalguni此答案的早期版本包含一個不正確的JavaScript函數。它現在已經修復。 – Philipp

+0

我執行以下查詢:db.runCommand({的MapReduce: 「訂單」, 圖:功能圖(){ \t \t EMIT(this._id,這一點); }, 減少:減少功能(鍵,值){ \t返回值; }, 最終化:功能的Finalize(鍵,還原的){ \t回報減少; }, 查詢:{ 「$其中」:「返回this.items.some(函數(entry){entry.sku =='mmm'})「}, out:{merge:」map_reduce「} });,但它不起作用 – Phalguni

+0

我得到了問題:查詢應該如下{$其中:「return this.items.some(function(entry){return entry.sku =='mmm'} )「},內函數缺少return語句 – Phalguni

2

您不需要$where運營商來做到這一點;只是使用的查詢對象:

{ "items.sku": mmm } 

至於爲什麼你$where不工作,該運營商的價值,如JavaScript執行,所以這不會檢查items陣列中的每個元素,它只是要將items視爲正常對象,並將其sku屬性(未定義)與mmm進行比較。

+0

我有一種情況,我必須同時使用,我的服務只是用戶和mongodb之間的接口,完全不知道現場客戶端要存儲什麼,所以如果客戶端通過一個鍵,如「items.sku ==嗯,「它應該工作,我知道我可以使用簡單的查詢,但是他們的解決方案與$ where – Phalguni

+0

因此,在這種情況下,可以用$ where子句添加」for循環「? – Phalguni

0

我一直在閱讀你的意見,除了問題。這聽起來像你的用戶可以一般地添加一些屬性,這些屬性存儲在文檔中的數組中。您的客戶需要能夠以通用的方式從文檔中查詢任意對。實現此目的的模式通常如下:

{ 
    . 
    . 
    attributes:[ 
    {k:"some user defined key", 
     v:"the value"}, 
    {k: ,v:} 
     . 
     . 
    ] 
} 

請注意,在您的情況下,項目是屬性。現在得到的文件,你的查詢將是這樣的:

eg) 
db.collection.find({attributes:{$elemMatch:{k:"sku",v:"mmm"}}}); 
(index attributes.k, attributes.v) 

這允許您服務,提供一種方法來查詢數據,並讓客戶指定什麼K,V對是。有了這個設計的一個警告總是知道文檔有16MB的限制(除非你有一個使GridFS適合的用例)。有像$ slice這樣的函數可以幫助控制這個。

+0

Dyalan你猜對了,但萬一用戶想要查詢類似這樣的東西以及「items.qty> 5」,在這種情況下,這將不起作用,我認爲最好使用「$ where」作爲@philip告訴。 – Phalguni

+0

你可以做這個查詢。例如:db.col.find({attributes:{$ elemMatch:{k0:「sku」,v0:「mmm」,k1:「qty」,v1:{$ gt:5}}}})。該索引可能看起來像db.col.ensureIndex({「attributes.k0」:1,「attributes.v0」:1,「attributes.k1」:1,「attributes.v1」:1,「attributes.k2」: 1, 「attributes.v2」:1}); –