2015-06-25 124 views
0

我有一個包含用戶名,電子郵件地址和一個版本,這是每一個用戶保存時間增加一個用戶對象。將用戶保存到Mongo時,更新查詢包含版本,如果用戶在保存之前修改了數據庫,則版本將會不同,因此用戶將不會保存。的Upsert有多個查詢條件

一個例子更新查詢: {"username":"name","version":6}

在某些情況下,我想,當我保存使用update用戶,他們的帳戶可能不會在這個階段被創建到使用UPSERT。在帳戶被加載後創建和修改的情況下,根據我的理解,它將嘗試創建新文檔,因爲查詢與任何文檔都不匹配。有沒有辦法只創建一個新的文檔,如果查詢的特定字段不匹配,例如用戶名?

+0

[**'$ setOnInsert' **](http://docs.mongodb.org/manual/reference/operator/update/setOnInsert/)應該允許您這樣做。 – chridam

回答

0

讓我們的用戶名作爲 'newUser1' 和收集稱爲 '用戶'

執行在蒙戈以下shell

如果(db.users.findOne({用戶名:newUser1}!)) {db.users.insert({用戶名:newUser1,電子郵件:[email protected],版本:1})}

注:我們需要提供準確的用戶名

0

看起來像您的問題聲明的是,

  1. 如果其他進程已更新了記錄,則因爲傳遞(在內存中)的版本比在數據庫中的一個已經存在的(最近由以前的進程更新)下的代碼不應該更新它。

  2. 然而,如果傳遞的版本等於已經存在的最大的版本,那麼它應該更新的一個。

  3. ,如果傳入的版本是嚴格更大,那麼它應該插入記錄。

您可以使用下面的代碼來實現它,但是這不是在生產環境中爲它不是一個語句中發生的事情,因此原子不能保證一個非常優雅的解決方案。可能不會像prod環境那樣非常優雅,但是您可以根據您的要求在其上構建它。

--in the variable userToUpdate, change the version to 0, 1 and 2 to see different types of behaviors as explained in the above 3 points. 

db.t1.drop(); //drop if exist 
db.t1.save({uname:"sachin", v:0, email:"email-0"}); 
db.t1.save({uname:"sachin", v:1, email:"email-1"}); 
//---- 
var userToUpdate = {uname:"sachin", v:2, email:"email-2"}; 
//---- 
var user = userToUpdate.uname; 
var cur = db.t1.find({uname:user}).sort({v:-1}).limit(1); 
var latestVersion = 0; 
if(cur.hasNext()){ 
    var v1 = cur.next(); 
    latestVersion = v1['v']; 
    printjson('latestVersion='+latestVersion); 
} 

versionToUpdate = (userToUpdate.v < latestVersion)? -1 : userToUpdate.v; 
if(versionToUpdate != -1){ 
    printjson('Going to upsert'); 
    db.t1.update({uname:user, v:versionToUpdate}, userToUpdate, {upsert:true}); 
}else{ 
printjson('latest version in db : '+latestVersion+', which is greater than the passed version '+userToUpdate.v+', hence ingoring'); 
}