MongoDB:使用来自同一文档的数据更新文档

我有一个文件列表,每个文件都具有经纬度属性(等等)。

{ 'lat': 1, 'lon': 2, someotherdata [...] } { 'lat': 4, 'lon': 1, someotherdata [...] } [...] 

我想修改它,看起来像这样:

 { 'coords': {'lat': 1, 'lon': 2}, someotherdata [...]} { 'coords': {'lat': 4, 'lon': 1}, someotherdata [...]} [...] 

到目前为止,我有这样的:

 db.events.update({}, {$set : {'coords': {'lat': db.events.lat, 'lon': db.events.lon}}}, false, true) 

但它将db.events.latdb.events.lon视为string。 我怎样才能参考文件的属性?

干杯。

$ rename操作符(在这个问题发布一个月后发布)可以很容易地完成这些你不需要修改值的事情。

插入一些testing文件

 db.events.insert({ 'lat': 1, 'lon': 2, someotherdata: [] }) db.events.insert({ 'lat': 4, 'lon': 1, someotherdata: [] }) 

使用$rename操作符

 db.events.update({}, {$rename: {'lat': 'coords.lat', 'lon': 'coords.lon'}}, false, true) 

结果

 db.events.find() { "_id" : ObjectId("5113c82dd28c4e8b79971add"), "coords" : { "lat" : 1, "lon" : 2 }, "someotherdata" : [ ] } { "_id" : ObjectId("5113c82ed28c4e8b79971ade"), "coords" : { "lat" : 4, "lon" : 1 }, "someotherdata" : [ ] } 

更新:如果您只需更改文档的结构而不更改值,请参阅gipset的答案以获得更好的解决scheme。


根据“ 更新文档”页面 (现在不可用)的评论,您不能在update()引用当前文档的属性。

你将不得不迭代所有的文件,并像这样更新它们:

 db.events.find().snapshot().forEach( function (e) { // update document, using its own properties e.coords = { lat: e.lat, lon: e.lon }; // remove old properties delete e.lat; delete e.lon; // save the updated document db.events.save(e); } ) 

这样的函数也可以在map-reduce作业或服务器端db.eval()作业中使用,具体取决于您的需要。

我们可以使用Mongo脚本来即时处理数据。 它适合我!

我使用这个脚本来纠正我的地址数据。

当前地址示例:“第十五大道12号”。

我想删除最后多余的逗号,预期的新地址“”No.12,FIFTH AVENUE“。

 var cursor = db.myCollection.find().limit(100); while (cursor.hasNext()) { var currentDocument = cursor.next(); var address = currentDocument['address']; var lastPosition = address.length - 1; var lastChar = address.charAt(lastPosition); if (lastChar == ",") { var newAddress = address.slice(0, lastPosition); currentDocument['address'] = newAddress; db.localbizs.update({_id: currentDocument._id}, currentDocument); } } 

希望这可以帮助!

尼尔回答 。 只是为了让人们知道你不能在一个大型的数据库上运行,如果你可以说像Robomongo这样的远程shell。 你将需要ssh进入你的实际服务器的mongo shell。 你也可以做这个,如果你宁愿做一个更新。

 db.Collection.find({***/ possible query /***}).toArray().forEach( function(obj){ obj.item = obj.copiedItem; obj.otherItem = obj.copiedItem; obj.thirdItem = true; obj.fourthItem = "string"; db.Collection.update({_id: obj._id}, obj); } ); 

只要您可以创build数据的副本,就可以在这里使用聚合框架作为替代。 如果你希望使用其他的操作符,你也可以select对数据做更多的事情,但是唯一需要的是$project 。 在空间方面有些浪费,但对某些用途可能更快,更合适。 为了说明,我将首先在foo集合中插入一些示例数据:

 db.foo.insert({ 'lat': 1, 'lon': 2, someotherdata : [1, 2, 3] }) db.foo.insert({ 'lat': 4, 'lon': 1, someotherdata : [4, 5, 6] }) 

现在,我们只需使用$project来修改latlon字段,然后将它们发送到newfoo集合:

 db.foo.aggregate([ {$project : {_id : "$_id", "coords.lat" : "$lat", "coords.lon" : "$lon", "someotherdata" : "$someotherdata" }}, { $out : "newfoo" } ]) 

然后检查我们改变的数据newfoo

 db.newfoo.find() { "_id" : ObjectId("544548a71b5cf91c4893eb9a"), "someotherdata" : [ 1, 2, 3 ], "coords" : { "lat" : 1, "lon" : 2 } } { "_id" : ObjectId("544548a81b5cf91c4893eb9b"), "someotherdata" : [ 4, 5, 6 ], "coords" : { "lat" : 4, "lon" : 1 } } 

一旦您对新数据感到满意,可以使用renameCollection()命令删除旧数据,并使用旧数据下的新数据:

 > db.newfoo.renameCollection("foo", true) { "ok" : 1 } > db.foo.find() { "_id" : ObjectId("544548a71b5cf91c4893eb9a"), "someotherdata" : [ 1, 2, 3 ], "coords" : { "lat" : 1, "lon" : 2 } } { "_id" : ObjectId("544548a81b5cf91c4893eb9b"), "someotherdata" : [ 4, 5, 6 ], "coords" : { "lat" : 4, "lon" : 1 } } 

最后一个注意事项 – 在SERVER-7944完成之前,通过暗示此答案中build议的_id索引,不能完成快照的等价操作,因此,如果其他地方的活动导致它移动,最终可能会多次打印文档。 由于在此示例中插入了_id字段,因此任何此类事件都将导致唯一的密钥违例,所以您不会以愚蠢的方式结束,但您可能拥有文档的“旧”版本。 与往常一样,请在删除之前彻底检查您的数据,最好进行备份。

从CLI? 我认为你必须先把这个值拉出来,然后把值赋给一个variables。 然后运行你的更新命令。

或者(我还没有尝试)从string中删除“数据库”。 events.latevents.lon如果有效,您仍然会有多个值,“lat”和“lon”的旧值以及您创build的新数组。