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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3788256/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 11:48:33  来源:igfitidea点击:

MongoDB: Updating documents using data from the same document

mongodb

提问by Pawel Decowski

I have a list of documents, each with lat and lon properties (among others).

我有一个文件列表,每个文件都有 lat 和 lon 属性(等等)。

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

I want to modify it so that it looks like this:

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

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

So far I've got this:

到目前为止,我有这个:

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

But it treats the db.events.latand db.events.lonas strings. How can I reference the document's properties?

但它将db.events.latdb.events.lon视为字符串。如何引用文档的属性?

Cheers.

干杯。

采纳答案by gipset

The $renameoperator (introduced a month after this question was posted) makes it really easy to do these kinds of things where you don't need to modify the values.

$重命名操作(介绍这个问题被张贴一个月后),使得它很容易做这些事情,你并不需要修改的值。

Insert some test documents

插入一些测试文件

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

use the $renameoperator

使用$rename运算符

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

Results

结果

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

回答by Niels van der Rest

Update:If all you have to do is change the structure of a document without changing the values, see gipset's answerfor a nice solution.

更新:如果您所要做的就是在不更改值的情况下更改文档的结构,请参阅gipset 的答案以获得一个不错的解决方案。



According to a (now unavailable) comment on the Update documentation page, you cannot reference the current document's properties from within an update().

根据更新文档页面上的(现在不可用)评论,您不能从update().

You'll have to iterate through all the documents and update them like this:

您必须遍历所有文档并像这样更新它们:

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);
  }
)

Such a function can also be used in a map-reduce job or a server-side db.eval()job, depending on your needs.

db.eval()根据您的需要,此类功能也可用于 map-reduce 作业或服务器端作业。

回答by mjwrazor

Neils answer. Just to let people know you cannot run this on a large database if you are lets say doing it remote shell like Robomongo. You will need to ssh into your actual server's mongo shell. Also you could also do this if you would rather do an Update.

尼尔斯回答。只是为了让人们知道你不能在大型数据库上运行它,如果你可以说它像 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);
  }
);

回答by Adam Comerford

As long as you are OK with creating a copy of the data, the aggregation framework can be used as an alternative here. You also have the option to do more to the data if you wish using other operators, but the only one you need is $project. It's somewhat wasteful in terms of space, but may be faster and more appropriate for some uses. To illustrate, I'll first insert some sample data into the foocollection:

只要您可以创建数据的副本,这里就可以使用聚合框架作为替代方案。如果您希望使用其他运算符,您还可以选择对数据执行更多操作,但您唯一需要的是$project. 它在空间方面有点浪费,但可能更快,更适合某些用途。为了说明这一点,我首先将一些示例数据插入到foo集合中:

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

Now, we just use $projectto rework the latand lonfields, then send them to the newfoocollection:

现在,我们只$project需要重新处理latlon字段,然后将它们发送到newfoo集合中:

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

Then check newfoofor our altered data:

然后检查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 } }

Once you are happy with the new data, you can then use the renameCollection()command to drop the old data and use the new data under the old name:

一旦您对新数据感到满意,您就可以使用该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 } }

One last note - until SERVER-7944is completed you can't do the equivalent of a snapshot by hinting the _idindex as suggested in this answerand so you can end up hitting a document more than once if activity elsewhere causes it to move. Since you are inserting the _idfield in this example, any such occurrence would cause a unique key violation, so you will not end up with dupes, but you might have an "old" version of a document. As always, check your data thoroughly before dropping it, and preferably take a backup.

最后一个注意事项 - 在完成SERVER-7944之前,您无法_id按照本答案中的建议提示索引来执行相当于快照的操作,因此如果其他地方的活动导致文档移动,您最终可能会多次点击文档。由于您_id在此示例中插入字段,因此任何此类事件都会导致唯一键冲突,因此您不会以欺骗结束,但您可能拥有文档的“旧”版本。与往常一样,在删除数据之前彻底检查您的数据,最好进行备份。

回答by Dac Nguyen

We can use Mongo script to manipulate data on the fly. It works for me!

我们可以使用 Mongo 脚本来动态操作数据。这个对我有用!

I use this script to correct my address data.

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

Example of current address: "No.12, FIFTH AVENUE,".

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

I want to remove the last redundant comma, the expected new address ""No.12, FIFTH AVENUE".

我想去掉最后一个多余的逗号,预期的新地址“第五大道12号”。

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);

  }
}

Hope this helps!

希望这可以帮助!

回答by luckytaxi

From the CLI? I think you have to pull the values out first and assign the value into a variable. Then run your update command.

从命令行界面?我认为您必须先提取值并将值分配给变量。然后运行您的更新命令。

Or (I haven't tried) remove 'db' from the string. events.latand events.lonIf it works, you will still have multiple values, the old values for "lat" and "lon" and the new array you created.

或者(我没试过)从字符串中删除 'db'。events.latevents.lon如果一切正常,你仍然有多个值,您创建了“纬度”和“经度”和新阵旧值。