2010-06-28 61 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