2014-02-08 74 views
3

我已經在LinkedIn上回答了這個問題,我認爲這是分享的有用和有趣的東西。這個問題是:MongoDB中的條件upsert

「假設我們有一個文件,如{_id: ..., data: ..., timestamp: ...}

有什麼辦法來寫的更新標準,這將滿足下列規則:

1如果沒有與以下_id沒有文件然後插入該文件;

2如果存在文件與以下_id然後

2.1如果新的時間戳大於存儲時間戳n更新data;

2.2,否則什麼都不做」的

回答

8

解決方案應該做的伎倆,你只需要忽略DUP鍵錯誤的例子是在蒙戈外殼下式給出:

> var lastUpdateTime = ISODate("2013-09-10") 
> var newUpdateTime = ISODate("2013-09-12") 
> 
> lastUpdateTime 
ISODate("2013-09-10T00:00:00Z") 
> newUpdateTime 
ISODate("2013-09-12T00:00:00Z") 
> 
> var id = new ObjectId() 
> id 
ObjectId("52310502f3bf4823f81e7fc9") 
> 
> // collection is empty, first update will do insert: 
> db.testcol.update(
... {"_id" : id, "ts" : { $lt : lastUpdateTime } }, 
... { $set: { ts: lastUpdateTime, data: 123 } }, 
... { upsert: true, multi: false } 
...); 
> 
> db.testcol.find() 
{ "_id" : ObjectId("52310502f3bf4823f81e7fc9"), "data" : 123, "ts" : ISODate("2013-09-10T00:00:00Z") } 
> 
> // try one more time to check that nothing happens (due to error): 
> db.testcol.update(
... {"_id" : id, "ts" : { $lt : lastUpdateTime } }, 
... { $set: { ts: lastUpdateTime, data: 123 } }, 
... { upsert: true, multi: false } 
...); 
E11000 duplicate key error index: test.testcol.$_id_ dup key: { : ObjectId('52310502f3bf4823f81e7fc9') } 
> 
> var tooOldToUpdate = ISODate("2013-09-09") 
> 
> // update does not happen because query condition does not match 
> // and mongo tries to insert with the same id (and fails with dup again): 
> db.testcol.update(
... {"_id" : id, "ts" : { $lt : tooOldToUpdate } }, 
... { $set: { ts: tooOldToUpdate, data: 999 } }, 
... { upsert: true, multi: false } 
...); 
E11000 duplicate key error index: test.testcol.$_id_ dup key: { : ObjectId('52310502f3bf4823f81e7fc9') } 
> 
> // now query cond actually matches, so update rather than insert happens which works 
> // as expected: 
> db.testcol.update(
... {"_id" : id, "ts" : { $lt : newUpdateTime } }, 
... { $set: { ts: newUpdateTime, data: 999 } }, 
... { upsert: true, multi: false } 
...); 
> 
> // check that everything worked: 
> db.testcol.find() 
{ "_id" : ObjectId("52310502f3bf4823f81e7fc9"), "data" : 999, "ts" : ISODate("2013-09-12T00:00:00Z") } 
> 

唯一惱人的部分是那些錯誤,但它們便宜且安全

-1
db.collection.update({ 
     _id: ObjectId("<id>")) 
     }, 
     {timestamp: <newTimestamp>, data: <data>}, 
     {upsert: true}) 

此操作將更新現有文檔,如果它符合存在條件並且現有時間戳較少比newTimestamp;否則會插入一個新的文件。

+1

這將是一個更好的例子,如果你解釋它爲什麼工作 –

+0

它不起作用 - 使用更新操作符和僅使用字段值僅有一個區別:http://docs.mongodb.org/manual/reference/method /db.collection.update/#update-parameter。 –

+0

@AlekseyIzmailov我同意有一個區別,但是,在這種情況下,文檔完全由三個字段定義:_id,時間戳和數據。這工作。 – Rishi