MongoDB-upsert包含列表

MongoDB-upsert包含列表,mongodb,nosql,Mongodb,Nosql,我是一个MongoDB新手,想问一下如何编写涉及upsert和list的更新命令 基本上,我想完成以下任务: {"_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 201

我是一个MongoDB新手,想问一下如何编写涉及upsert和list的更新命令

基本上,我想完成以下任务:

{"_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"}]
    }
]}
> db.mycollection.find({"application_id":"MyTestApp"})          
{ "_id" : ObjectId("4c29044ebf8544c60506f11f"), 
"application_id" : "MyTestApp", 
"trips" : { "$" : { "loc" : [ { "lat" : 11, "lng" : 11 } ] }, 
"name" : "2010-05-10" } 
}
请注意:

  • 您提供旅行名称和 当前位置
  • 如果行程不存在,则它将 需要创建
  • trips.name应该是唯一的,以便 如果存在,则将其附加到 位置阵列
这是我结合positional操作符和$push编写的查询

    db.mycollection.update({"application_id": "MyTestApp", 
                            "trips.name": "2010-05-10"},
                           {$push: {'trips.$.loc': {"lat":11, "lng":11} }}, 
                           true);
但这会产生如下数据:

{"_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"}]
    }
]}
> db.mycollection.find({"application_id":"MyTestApp"})          
{ "_id" : ObjectId("4c29044ebf8544c60506f11f"), 
"application_id" : "MyTestApp", 
"trips" : { "$" : { "loc" : [ { "lat" : 11, "lng" : 11 } ] }, 
"name" : "2010-05-10" } 
}
你可以看到

  • “trips”不是数组
  • 它从字面上取了“$”并创建了一个 用那个键(doh!)
到目前为止,我对MongoDB非常满意,但编写复杂的查询肯定会有一个陡峭的学习曲线

任何反馈都将不胜感激

提前感谢,,
Amie

编辑以包含正确的解决方案

这正是我在learning Mongo中遇到的问题-您正在查找与
update
命令一起使用的
$addToSet
操作符(),该操作符与您使用的
$
位置操作符一起使用

$addToSet

{$addToSet:{field:value}

仅当其不在数组中时才向数组添加值

因此,查询变成(db.stack是我用于测试目的的集合),下面是运行示例:

db.stack.update({ "trips.name":"2010-05-10" }, 
                { $addToSet: { "trips.$.loc":{"lat":11, "lng":12} } }
               );
测试运行(使用一些不重要的元素空间缩写):


不能混合使用位置运算符($)和upsert;插入期间,“$”将被视为字段名。不能对新文档执行此操作,只能对现有文档执行此操作

我提出了一个更像这样的结构:

{"_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.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.update({application_id: "MyTestApp", "trips.2010-05-10":{$exists:true}},
                       {$push: {"trips.2010-05-10": {lat:11, lng:11} }}, 
                       true);
结果将插入此文件

> 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 } ] } }

感谢您的回复@Anthony Morelli。我尝试了$addToSet,并且必须传入upsert=true才能第一次插入trip。当我将行程名称更改为其他名称时,实际上会创建一个新文档,而不是使用当前文档。我们如何指定“trips”是一个数组?您具体运行了什么查询$addToSet仅适用于数组,因此我认为规范不是问题所在。我准确地运行了您的查询,但它没有创建文档,因此我传入了upsert=true。在创建第一个文档之后,当它第二次运行时,它创建了第二个文档,而不是将其附加到前一个文档中..我相信我已经修复了它-请参阅编辑。基本上,我忘记了位置操作符,它是指定trips数组中应该更新的项所必需的。新的查询是
db.stack.update({“trips.name”:“2010-05-10”},{$addToSet:{“trips.$.loc”:{“lat”:11,“lng”:12}}})-我用您现有的模式对其进行了测试,效果很好。如果说只有在文档已经存在的情况下才有效,是否正确?(正如Scott指出的,我们不能同时使用“$”和upsert),但我可以看出这在某些情况下是有用的。感谢全面的更新!这与我试图实现的目标非常接近。谢谢@Scott Hernandez。使用此模式,是否可以检索“trips”中的键列表?(“2010-050-10”,等等)db.mycollection.find({“application_id”:“MytestApp”},{“trips”:true})返回整个“trips”散列。我最终使用了这个方法。谢谢你的解决方案,斯科特!这里的问题是,您无法在行程中查询某些内容,例如查找行程为lat 21.321231的文档(因为mongo(今天)无法找到字段路径的“通配符”部分)。再次检查我下面的答案-我对其进行了编辑,以包括我认为是解决方案的内容(或者至少是应该让您非常接近的内容)看这个。类似的东西。