2010-06-28 76 views
5

我是一個MongoDB新手,想問如何編寫涉及upsert和列表的更新命令。MongoDB - upsert涉及列表

基本上我要完成這樣的事情:那

{"_id" : ObjectId("4c28f62cbf8544c60506f11d"), 
"some_other_data":"goes here", 
"trips": [ 
    {"name": "2010-05-10", 
    "loc": [{"lat":21.321231, "lng": 16.8783234, "updated_at": "Mon May 10 2010 15:24:35"}, 
     {"lat":21.321231, "lng": 16.8783234, "updated_at": "Mon May 10 2010 15:24:24"}] 
    }, 
    {"name": "2010-05-08", 
    "loc": [{"lat":21.324239, "lng": 16.8735234, "updated_at": "Mon May 8 2010 11:18:05"}, 
     {"lat":21.311234, "lng": 16.8743271, "updated_at": "Mon May 8 2010 11:17:55"}, 
     {"lat":21.321238, "lng": 16.8782219, "updated_at": "Mon May 8 2010 11:17:45"}] 
    } 
]} 

注:

  • 您如果行程不存在提供行程名稱和 當前位置
  • ,它需要創建
  • trips.name應該是唯一的,以便 如果它存在ts,您追加到 位置數組

這是我寫的位置操作符與$ push相結合的查詢。

db.mycollection.update({"application_id": "MyTestApp", 
          "trips.name": "2010-05-10"}, 
          {$push: {'trips.$.loc': {"lat":11, "lng":11} }}, 
          true); 

但是,這會導致數據是這樣的:

> db.mycollection.find({"application_id":"MyTestApp"})   
{ "_id" : ObjectId("4c29044ebf8544c60506f11f"), 
"application_id" : "MyTestApp", 
"trips" : { "$" : { "loc" : [ { "lat" : 11, "lng" : 11 } ] }, 
"name" : "2010-05-10" } 
} 

你可以看到,

  • 「旅行」 是不是數組
  • 花 「$」 的字面和創建一個 鑰匙與那(doh!)

到目前爲止,我對MongoDB一直非常滿意,但編寫複雜查詢的確存在陡峭的學習曲線。

任何反饋將不勝感激。

由於提前, 阿米

+0

再次檢查我的回答如下 - 我編輯它包含了我認爲是解決(或者至少東西,應該讓你非常接近) – nearlymonolith 2010-06-30 21:17:50

+0

看到此[SO主題](http://stackoverflow.com/questions/17994552/mongodb-update-documents-in-anray/17995495#17995495)。 與此類似的東西。 – user10 2013-08-01 13:32:21

回答

4

你可以不要混合位置操作符(「$」)和頂點;在插入過程中「$」將被視爲字段名稱。您無法爲新文檔執行此操作,只能使用現有文檔。

我提出了一個結構更加是這樣的:在這個被插入

db.mycollection.update({application_id: "MyTestApp", "trips.2010-05-10":{$exists:true}}, 
         {$push: {"trips.2010-05-10": {lat:11, lng:11} }}, 
         true); 

結果:

{"_id" : ObjectId("4c28f62cbf8544c60506f11d"), 
"some_other_data":"goes here", 
"trips": { 
    "2010-05-10": 
     [{"lat":21.321231, "lng": 16.8783234, "updated_at": "Mon May 10 2010 15:24:35"}, 
     {"lat":21.321231, "lng": 16.8783234, "updated_at": "Mon May 10 2010 15:24:24"}], 
    "2010-05-08": 
     [{"lat":21.324239, "lng": 16.8735234, "updated_at": "Mon May 8 2010 11:18:05"}, 
     {"lat":21.311234, "lng": 16.8743271, "updated_at": "Mon May 8 2010 11:17:55"}, 
     {"lat":21.321238, "lng": 16.8782219, "updated_at": "Mon May 8 2010 11:17:45"}] 
    } 
} 

然後你就可以發出一個更新這樣的。

> db.mycollection.find() 
{ "_id" : ObjectId("4c2931d17b210000000045f0"), 
    "application_id" : "MyTestApp", 
    "trips" : { "2010-05-10" : [ { "lat" : 11, "lng" : 11 } ] } } 

並再次運行它給你:

> db.mycollection.find() 
{ "_id" : ObjectId("4c2932db7b210000000045f2"), 
    "application_id" : "MyTestApp", 
    "trips" : { "2010-05-10" : 
     [ { "lat" : 11, "lng" : 11 }, 
      { "lat" : 11, "lng" : 11 } ] } } 
+0

這與我試圖實現的非常接近。謝謝@Scott Hernandez。有了這個模式,是否有可能在「旅行」中檢索密鑰列表? (「2010-050-10」等)db.mycollection.find({「application_id」:「MytestApp」},{「trips」:true})返回整個「旅行」散列。 – Grnbeagle 2010-06-29 18:10:44

+0

我結束了這個方法。感謝Scott的解決方案! – Grnbeagle 2010-07-12 06:42:52

+0

存在的問題是,您無法查詢行程內的某些內容,例如查找具有拉特21.321231行程的文檔(因爲mongo(今天)無法通往該字段的'通配符'部分)。 – Nick 2013-01-04 19:27:53

1

編輯,包括正確的解決方案

這就是我打的學習蒙戈的問題 - 你正在尋找的$addToSet運營商(see docs here),這與使用update命令,以及您正在使用的位置操作符$

$ addToSet

{$ addToSet:{字段:值}}

增加價值,只有數組如果不是數組中了。

查詢因此變成(db。堆棧是我用於測試目的)收集,樣品運行遵循:

db.stack.update({ "trips.name":"2010-05-10" }, 
       { $addToSet: { "trips.$.loc":{"lat":11, "lng":12} } } 
       ); 

TEST RUN(有一些縮寫是不重要的元素)的空間:

#### YOUR ITEM IN THE DB 
> db.stack.find({"trips.name":"2010-05-10"}) 
{ "_id" : ObjectId("4c28f62cbf8544c60506f11d"), "some_other_data" : "goes here", 
    "trips" : [ 
    { "name" : "2010-05-10", 
     "loc" : [ { 
       "lat" : 21.321231, 
       "lng" : 16.8783234, 
       "updated_at" : "Mon May 10 2010 15:24:35" 
      }, { "lat" : 21.321231, 
       "lng" : 16.8783234, 
       "updated_at" : "Mon May 10 2010 15:24:24" 
      } ] }, 
    { "name" : "2010-05-08", 
     "loc" : [ ... ] 
    } ] } 
#### SUCCESSFULLY ADDS ITEM TO PROPER ARRAY 
> db.stack.update({"trips.name":"2010-05-10"}, {$addToSet: {"trips.$.loc":{"lat":11, "lng":11}}}); 
> db.stack.findOne() 
{ "_id" : ObjectId("4c28f62cbf8544c60506f11d"), "some_other_data" : "goes here", 
    "trips" : [ 
     { "loc" : [ 
       { "lat" : 21.321231, 
        "lng" : 16.8783234, 
        "updated_at" : "Mon May 10 2010 15:24:35" 
       }, { "lat" : 21.321231, 
        "lng" : 16.8783234, 
        "updated_at" : "Mon May 10 2010 15:24:24" 
       }, { "lat" : 11, 
        "lng" : 11 
       } 
      ], "name" : "2010-05-10" 
     }, 
     { "name" : "2010-05-08", 
      "loc" : [ ... ] 
     } ] } 
#### ON REPEAT RUN DOESN'T ADD NEW ELEMENT 
> db.stack.update({"trips.name":"2010-05-10"}, {$addToSet: {"trips.$.loc":{"lat":11, "lng":11}}}); 
> db.stack.findOne() 
{ "_id" : ObjectId("4c28f62cbf8544c60506f11d"), "some_other_data" : "goes here", 
    "trips" : [ { 
      "loc" : [ 
       { "lat" : 21.321231, 
        "lng" : 16.8783234, 
        "updated_at" : "Mon May 10 2010 15:24:35" 
       }, { "lat" : 21.321231, 
        "lng" : 16.8783234, 
        "updated_at" : "Mon May 10 2010 15:24:24" 
       }, { "lat" : 11, 
        "lng" : 11 
       } 
      ], "name" : "2010-05-10" 
     }, 
     { "name" : "2010-05-08", 
      "loc" : [ ... ] 
     } ] } 
#### BUT WILL CORRECTLY ADD ANOTHER ELEMENT TO THE SAME ARRAY IF IT'S NOT PRESENT 
> db.stack.update({"trips.name":"2010-05-10"}, {$addToSet: {"trips.$.loc":{"lat":11, "lng":12}}}); 
> db.stack.findOne() 
{ "_id" : ObjectId("4c28f62cbf8544c60506f11d"), "some_other_data" : "goes here", 
    "trips" : [ 
     { "loc" : [ 
       { "lat" : 21.321231, 
        "lng" : 16.8783234, 
        "updated_at" : "Mon May 10 2010 15:24:35" 
       }, { "lat" : 21.321231, 
        "lng" : 16.8783234, 
        "updated_at" : "Mon May 10 2010 15:24:24" 
       }, { "lat" : 11, 
        "lng" : 11 
       }, { "lat" : 11, 
        "lng" : 12 
       } 
      ], "name" : "2010-05-10" 
     }, 
     { "name" : "2010-05-08", 
      "loc" : [ ... ] 
    } ] } 
+0

感謝@安東尼莫雷利的迴應。我嘗試了$ addToSet,並且必須通過upsert = true來首次插入行程。當我將旅程名稱更改爲其他內容時,實際上會創建一個新文檔而不是使用當前文檔。我們如何指定「旅行」是一個數組? – Grnbeagle 2010-06-28 21:21:51

+0

您具體運行了哪個查詢? $ addToSet只適用於數組,所以我不認爲這個規範是問題。 – nearlymonolith 2010-06-29 13:25:21

+0

我完全運行了你的查詢,它沒有創建一個文檔,所以我通過了upsert = true。創建第一個文檔後,當它第二次運行時,它創建了第二個文檔,而不是將其附加到前一個文檔。 – Grnbeagle 2010-06-29 18:08:13