MongoDB: обновление документов с использованием данных из одного документа [дубликат]


этот вопрос уже есть ответ здесь:

у меня есть список документов, каждый из которых имеет свойства lat и lon (среди прочих).

{ '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)

но он лечит дБ.события.лат и дБ.события.Лон как струны. Как я могу ссылаться на свойства документа?

ваше здоровье.

6 74

6 ответов:

The $ rename оператор (введенный через месяц после публикации этого вопроса) позволяет очень легко делать такие вещи, когда вам не нужно изменять значения.

вставьте некоторые тестовые документы

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 это для хорошего решения.


согласно (теперь недоступно) комментарий на обновить страницу документации, вы не можете ссылаться на свойства текущего документа из 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() работа, в зависимости от ваших потребностей.

мы можем использовать скрипт Монго для управления данными на лету. Это работает для меня!

Я использую этот скрипт для исправления моих адресных данных.

пример текущего адреса: "№ 12, Пятая авеню,".

Я хочу удалить последнюю лишнюю запятую, ожидаемый новый адрес ""№ 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);

  }
}

надеюсь, что это помогает!

пока вы в порядке с созданием копии данных, структура агрегации может использоваться в качестве альтернативы здесь. У вас также есть возможность сделать больше для данных, если вы хотите использовать другие операторы, но вам нужно только $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 переработать lat и lon поля, а затем отправить их в 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 } }

последнее замечание-пока сервер-7944 завершена вы не можете сделать эквивалент снимка, намекая на как было предложено в ответ и поэтому вы можете в конечном итоге ударить документ более одного раза, если активность в другом месте заставляет его двигаться. Так как вы вставляете _id поле в этом примере любое такое событие вызовет нарушение уникального ключа, поэтому вы не будете в конечном итоге с обманом, но у вас может быть "старая" версия документа. Как всегда, тщательно проверьте свои данные перед их удалением и предпочтительно сделайте резервную копию.

Нэилс ответ. Просто чтобы люди знали, что вы не можете запустить это в большой базе данных, если вы, скажем, делаете это удаленной оболочкой, такой как Robomongo. Вам нужно будет ssh в оболочку mongo вашего фактического сервера. Также вы можете также сделать это, если вы хотите сделать обновление.

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

от CLI? Я думаю, что вы должны сначала вытащить значения и присвоить значение переменной. Затем запустите команду обновления.

или (я не пробовал) удалить ' db ' из строки. events.lat и events.lon Если это работает, вы все равно будете иметь несколько значений, старые значения для "lat" и "lon" и новый массив, который вы создали.