2011-12-01 56 views
25

我一直在尋找一種方法來創建一個更新語句,它將採用現有數字字段並使用表達式對其進行修改。例如,如果我有一個名爲Price的字段,是否可以執行更新,將Price設置爲現有值的50%?在Mongodb中按值乘以字段

因此,鑑於{ Price : 19.99 }

我想做db.collection.update({tag : "refurb"}, {$set {Price : Price * 0.50 }}, false, true);

可以這樣做或做我要讀值回客戶端,修改,然後更新?我想問題是可以在更新中使用表達式,並且他們可以引用正在更新的文檔。

+3

請注意,在蒙戈的即將推出的版本,你可以做到這一點沒有這一切的評估和DB在沒有成本幾乎鎖定。檢查並可能接受新答案,以便新開發者不會使用過時的信息。 –

回答

34

您可以使用db.eval()運行服務器端代碼。

db.eval(function() { 
    db.collection.find({tag : "refurb"}).forEach(function(e) { 
     e.Price = e.Price * 0.5; 
     db.collection.save(e); 
    }); 
}); 

注意這會阻止數據庫,所以最好是查找更新操作對。

http://www.mongodb.org/display/DOCS/Server-side+Code+Execution

+0

謝謝。你是說我應該像使用eval()一樣使用eval(),還是應該在查找/更新的時候使用eval()來避免阻塞? – Brad

+1

@Brad您應該評估此特定更新操作的總體成本。如果操作將會很長(集合中的許多文檔將被更新),您不應該使用eval。首先查詢文檔,然後進行更新而不是就地更新沒有太大的開銷。特別是如果您限制查詢大文檔的字段並使用覆蓋索引功能(http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields#RetrievingaSubsetofFields-CoveredIndexes) – pingw33n

+1

很酷,謝謝。我也看到eval()不能與分片一起工作,因此無論如何都要長期規則。 Nolock是一個有趣的補充。 – Brad

-1

好了,這是可能的原子操作$設置。

您有幾種選擇:

  • 使用由pingw33n
  • 提出的eval()解決方案檢索要修改,以獲得當前值和一組
  • ,如果你修改了文件有很高的操作速度,您可能想要確保在您獲取其值時(使用以前的解決方案),您的焦點沒有改變,因此您可能想要使用findAndModify(請參閱this page以獲取靈感如何執行操作)操作。

這真的取決於你的上下文:db的壓力非常低,我會去尋找pingw33n的解決方案。由於運行率非常高,我會使用第三種解決方案。

+0

謝謝。我看不出findAndModify如何允許使用表達式,這是我的主要目標。 – Brad

+0

@Brad findAndModify確實允許使用表達式,但它允許進行兩個階段的動作:首先獲取該項目,然後更新它(僅減少50%),因爲它自從檢索以來沒有改變 – kamaradclimber

19

在新的Mongo 2.6.x$mul operator。它會將字段的值乘以數字,並使用以下語法。

{ 
    $mul: { field: <number> } 
} 

所以你的情況,你需要做到以下幾點:

db.collection.update(
    { tag : "refurb"}, 
    { $mul: { Price : 0.5 } } 
); 
+1

我沒有足夠高代表評論,否則這將是對薩爾瓦多達利上面的帖子的評論,這幫助我,但格式錯誤。它應該是:{$ mul:{field:}} Not {field:{$ mul:}} – Wake