2014-02-13 99 views
1

更新方法中的Upsert功能很棒,但似乎它有一個很大的缺點,而且我找不到合理的解決方案。更新一個字段或插入很多(如果不存在)

問題是我想更新只有一個字段,如果有結果找到匹配的查詢條件,但沒有找到行,我想插入很多字段。

例如,如果發現({名:約翰,姓:康納})返回結果,我要爲他的只有新時代像{年齡:33},但如果發現沒有結果,我想插入很多領域,像{名字:約翰,姓:康納,年齡:32,作用:指揮官,性格:謹慎,愛好:「殺終結」}

有一個漂亮的方式來實現這在一個查詢?或者唯一的解決方案是直接的解決方案,意思是查找,檢查找到多少結果,並基於它插入或更新?

編輯:我補充說明了一步完成此功能的必要性。如果有人努力尋找並更新/插入,那麼分兩步完成的解決方案(首先查找,然後插入/更新)是很好的,但是如果有1000名工作人員嘗試這樣做,這會失敗 - 在結果除非我爲Name-Surname對(以某種方式)創建唯一索引,否則數據庫中可能會有很多John Connors(當第一對工作人員將找不到任何結果並且它們全部插入新行時)。但我正在尋找解決方案,不這樣做。

+0

我做我的項目和我一樣第一次使用它的方式檢查,如果沒有記錄,然後插入,如果有則更新它,所以這兩個查詢,但只有一個經過我的檢查 –

+0

後會跑我認爲DB不應該實現這個邏輯。這只是你程序的邏輯,爲什麼它應該在數據庫中?你應該檢查find查詢是否返回任何東西(這裏你可以使用limit 1來只檢查是否存在),並執行一個或另一個更新查詢。這不是DB的邏輯...... –

+0

問題是,當你有1000名想要插入的工作人員時,使用upsert可以讓你說,線程安全。使用兩個步驟(查找和更新/插入),可能會導致有一個以上的JC,除非你設置姓名爲唯一索引(但我不如何設置他們是唯一隻爲一對名字,姓氏,除非使一個連接它們,使其獨特的額外字段) – kaytrance

回答

4

你需要匹配上有足夠的條件來選擇特定的文檔,使用本文檔中的精確值,然後發送所有數據這將是必要的,如果它沒有存在來創建文檔。另外,如果文檔不存在,您需要指定upsert選項來創建文檔。

update({name: "John", surname: "Connor" }, 
     { $set : 
      {name: "John", surname: "Connor", age: 32, terminated: false}}, 
     { upsert: true }) 

請確保您瞭解使用upsert的性質。查詢需要依賴於唯一的字段,否則最終可能會生成多個具有匹配數據的文檔。

警告爲了避免將相同的文檔超過一次,只使用 UPSERT:如果查詢字段是唯一索引

的MongoDB不支持的方式有條件地更新的只是部分取決於查詢結果的文檔。有東西,使:

updateIf(query, updateIfTrue, updateIfFalse, options) 

選擇性地更新部分,則需要通過使用$set執行多個步驟或更新整個文檔。

+0

當我只想改變一個變量時,@Jinxcat解決方案也會失敗,當其中兩個變化的時候。由於這一點,如果我發送創建新行所需的所有數據,兩個新值也將被存儲,但這不是我想要的。 – kaytrance

+0

我不明白。 「他們兩個人?」什麼是「他們」?我已經增加了一點,說什麼不存在。 – WiredPrairie

+0

想象一下,我們有一個像_id這樣的行和另外6個變量(讓它們命名爲var1,var2,... var6)在集合中。從某個系統我收到新的6個變量值。爲了存儲我需要的內容,我通過var1和var2進行搜索。如果找到了(意味着在var1和var2中有精確值的集合中已經有一行),我只需要更新它的var3值,就像以前一樣。如果找不到,我需要插入一個包含所有6個變量的新行。因此,如果我爲當前的var1和var2接收到​​新的var3和var5,則只需要更新var3值,而不是var3和var5.這就是我的意思之一「其中之一」。 – kaytrance

1

您可以通過匹配完整文檔屬性除要更新的屬性除外)來獲得所需的功能。下面的例子:

插入集合中的唯一文件:

db.collection.insert({ name: "John", surname: "Connor", age: 32, role: "commander", character: "cautious", hobby: "kill terminators" }) 

現在

db.collection.find({"name" : "John", "surname" : "Connor", "role" : "commander", "character" : "cautious", "hobby" : "kill terminators" }) 

回報:

{ "_id" : ObjectId("52fc9a02d342217e6262aa28"), "name" : "John", "surname" : "Connor", "age" : 32, "role" : "commander", "character" : "cautious", "hobby" : "kill terminators" } 

update語句

db.collection.update({"name" : "John", "surname" : "Connor", "role" : "commander", "character" : "cautious", "hobby" : "kill terminators" },{$set:{age:33}}, { upsert: true }) 

更新現有文檔的屬性「年齡」:

{ "_id" : ObjectId("52fc9a02d342217e6262aa28"), "name" : "John", "surname" : "Connor", "age" : 33, "role" : "commander", "character" : "cautious", "hobby" : "kill terminators" } 

如果運行完全相同的更新語句更改名稱(因此,查找查詢不會找到一個現有的文件):

db.collection.update({"name" : "Robot", "surname" : "Connor", "role" : "commander", "character" : "cautious", "hobby" : "kill terminators" },{$set:{age:33}}, { upsert: true }) 

「機器人康納」的文件將被創建,33歲,和你結束了自己收藏的兩份文件:

db.collection.find() 

{ "_id" : ObjectId("52fc9a02d342217e6262aa28"), "name" : "John", "surname" : "Connor", "age" : 33, "role" : "commander", "character" : "cautious", "hobby" : "kill terminators" } 
{ "_id" : ObjectId("52fc9a5f56641f5e1b883677"), "age" : 33, "character" : "cautious", "hobby" : "kill terminators", "name" : "Robot", "role" : "commander", "surname" : "Connor" } 

注:我不相信更新的查詢參數上的額外屬性會對性能產生影響。

+0

我無法匹配所有屬性,因爲在我的示例中,我會在記錄上找到(因爲現在的年齡爲:32),結果將插入新的John Connor。 – kaytrance

+0

是的,你可以。您只是忽略搜索模式的年齡。查看更新的答案。 – Jinxcat

+0

只有年齡真正變化時,這纔有效,但如果年齡和愛好發生變化,這種方法就無效,但我只想更新年齡。這就是爲什麼我嚴格希望能夠定義要搜索的內容,如果找到要更新的內容以及如果沒有找到要更新的內容。似乎唯一合理的方法是在Name和Surname上添加複合唯一索引(以確保不會同時創建雙行),並根據查找結果進行常規查找+條件插入/更新。 – kaytrance

相關問題