2015-06-20 44 views
3

我正在處理一個需要使用Mongo查詢的高效數據集。該應用程序使用Ford-Fulkerson算法來計算建議並以多項式時間運行,因此效率非常重要。語法是ES6,但一切基本相同。

這是我正在使用的數據的近似值。項目和一個項目的數組被匹配了對其他項目:

let items = ["pen", "marker", "crayon", "pencil"]; 
let match = "sharpie"; 

最後,我們將遍歷match和1.因此增加了配對的權重,通過函數去後,我的理想數據看起來是這樣的:

{ 
    sharpie: { 
    pen: 1, 
    marker: 1, 
    crayon: 1, 
    pencil: 1 
    } 
} 

爲了進一步詳細描述,旁邊的每個鍵的值是關係,這是說,這些項目已經配對在一起的次數的weight。我想有發生的情況是這樣的:

// For each in the items array, check to see if the pairing already 
// exists. If it does, increment. If it does not, create it. 
_.each(items, function(item, i) { 
    Database.upsert({ match: { $exist: true }}, { match: { $inc: { item: 1 } } }); 
}) 

的問題,當然,是蒙戈不允許括號標記,也不允許變量名作爲關鍵字(match)。據我所知,另一個問題是Mongo在嵌套深的$inc運營商('The dollar ($) prefixed field \'$inc\' in \'3LhmpJMe9Es6r5HLs.$inc\' is not valid for storage.' })上也存在問題。

有什麼我可以做的儘可能少的查詢做到這一點?我接受建議。

編輯

我試圖創建對象,以傳遞到蒙戈查詢:

_.each(items, function(item, i) { 
     let selector = {}; 
     selector[match] = {}; 
     selector[match][item] = {}; 

     let modifier = {}; 
     modifier[match] = {}; 
     modifier[match]["$inc"] = {}; 
     modifier[match]["$inc"][item] = 1 

     Database.upsert(selector, modifier); 

不幸的是,它仍然無法正常工作。 $inc打破了查詢,它不會讓我超過1級深入任何改變。

解決方案

這是我最終實現的功能。它像一個魅力!謝謝馬特。

_.each(items, function(item, i) { 

    let incMod = {$inc:{}}; 
    let matchMod = {$inc:{}}; 

    matchMod.$inc[match] = 1; 
    incMod.$inc[item] = 1; 

    Database.upsert({node: item}, matchMod); 
    Database.upsert({node: match}, incMod); 
    }); 
+0

由於不能直接在參數中使用變量,並且不支持括號表示法,所以必須在調用Mongo查詢之前編程創建查詢對象。 http://stackoverflow.com/questions/22331216/programmatically-updating-fields-in-mongo-and-meteor – fuzzybabybunny

+0

@fuzzybabybunny謝謝你的回覆:)我試過使用查詢對象,但'$ inc'沒有出現深入發揮功能。有什麼想法嗎? – samcorcos

+0

「邊緣」是什麼意思? Mongo中沒有'邊緣'操作符。另外,'modifier [「edge」] [「$ inc」] [item] = 1'沒有定義變量'item'。你的意思是'el'? – fuzzybabybunny

回答

2

我覺得麻煩來自您的ER模型。一個sharpie不是一個獨立的實體,尖銳的是一個項目。 1項目與其他項目之間的關係是這樣的:1項目具有許多項目(1:M遞歸),並且每個項目配對具有權重。

完全標準化,你會有一個項目表&一個權重表。項目表將包含項目。權重表應該有類似item1,item2,weight(這樣做的話,你可以有不對稱的權重,例如sharpie:pencil = 1,pencil:sharpie = .5,這在計算FFA推回時很有用,但我認爲這不適用於你的情況。

太好了,現在讓我們mongotize它。

當我們說1個項目有很多項目,即「多」是可能不會超過幾千(認爲16MB文件帽),這意味着它實際上1-這意味着我們可以使用子目錄或字段嵌套數據。

所以,讓我們來看看這個模式!

doc = 
{ 
    _id: "sharpie", 
    crayon: 1, 
    pencil: 1 
} 

我們看到了什麼? sharpie不是關鍵,它是的值。這使一切變得簡單。我們將項目作爲字段保留。我們不使用對象數組的原因是因爲這是更快的清理器(不需要迭代數組以找到匹配的_id)。

var match = "sharpie"; 
var items = ["pen", "marker", "crayon", "pencil"]; 
var incMod = {$inc:{}}; 
var matchMod = {$inc:{}}; 
matchMod.$inc[match] = 1; 
for (var i = 0; i < items.length; i++) { 
    Collection.upsert({_id: items[i]}, matchMod); 
    incMod.$inc[items[i]] = 1; 
} 
Collection.upsert({_id: match}, incMod); 

這是很容易的部分。困難的部分是弄清楚爲什麼你想使用FFA作爲建議引擎:-P。

+0

我會盡力實現這:)現在看起來很有前景! – samcorcos

+0

它完全工作!馬特,你是男人!我不確定我完全理解'incMod'和'matchMod'發生了什麼,但它運行得非常完美。 我使用FFA只是爲了踢:)我也計劃實施一些其他算法。 – samcorcos

+0

當你有類似於{$ inc:{item:1}}的東西時,它只是一個帶有字段的對象。就像常規的JS對象一樣,您可以通過括號表示動態添加字段。 其次,將您的inc mod從循環中移出以減少觸摸到數據庫的次數。對於任何「交易」(我使用這個術語鬆散),你不應該多次觸摸相同的文檔。 第三,你跟什麼算法?協作過濾器? –

相關問題