Изменение типа mongodb в массив

У меня есть поле в mongodb, которое содержит строку. {"field": "some text"}, я хочу преобразовать их все в массивы. {"field": ["some text"]}

Я знаю, что могу просто пропустить все документы, получить поле, а затем обновить, но мне интересно, есть ли более чистый способ.

Спасибо.

Ответы

Ответ 1

Вы можете сделать это в функции уменьшения функции map/reduce, чтобы сохранить всю обработку в mongodb. По существу, вы должны использовать map/reduce, чтобы поместить результаты в новую коллекцию, а затем вы можете скопировать их обратно в старую коллекцию (или удалить старый и переименовать новую). Преимущество состоит в том, чтобы держать все внутри монго.

Обновить. Для этого можно использовать db.eval. db.eval выполняется на сервере, поэтому обновления будут выполняться на сервере без какого-либо трафика/задержки.

Я думаю, что единственный вариант, как вы описали, - сделать это на клиенте, запросив и обновив каждый.

Ответ 2

Ответ Nitin Garg выше почти работает, за исключением того, что его пример преобразуется из строки в хэш, а не в строку массива.

Принимая во внимание комментарии Джоэла Харриса, правильное решение будет выглядеть так:

db.jobs.find( { "jobLocationCity" : { $type : 2 } } ).snapshot().forEach( function (x) {
    x.jobLocationCity = [ jobLocationCity ];
    db.jobs.save(x);
});

Или если используется db.eval:

function f() {
    db.jobs.find( { "jobLocationCity" : { $type : 2 } } ).snapshot().forEach( function (x) {
        x.jobLocationCity = [ jobLocationCity ];
        db.jobs.save(x);
    });
}
db.eval(f);

Ответ 3

Фактически, find ({ "jobLocationCity": {$ type: 2}}) не будет работать должным образом, потому что если вы запустите обновление script в следующий раз, он снова будет обрабатывать элементы ['mystring'] как строковый тип.

Вы должны использовать что-то вроде этого, чтобы предотвратить это:

db.message_info.find( { "jobLocationCity" : { $type : 2 } }  ).snapshot().forEach(
  function (x) {
    if (!Array.isArray(x.jobLocationCity)){
        x.jobLocationCity = [ x.jobLocationCity  ];
        db.jobs.save(x);
    }
  }
)

см. http://docs.mongodb.org/manual/reference/operators/

Ответ 4

попробуйте это вместо

Это изменение типа поля из строки в массив в mongoDB

db.jobs.find( { "jobLocationCity" : { $type : 2 } } ).forEach( function (x) {
    x.jobLocationCity = {"Location":x.jobLocationCity};
    db.jobs.save(x);
});

см. ссылку для $type возможные значения

Ответ 5

но мне интересно, есть ли более чистый способ.

Короткий ответ - нет.

MongoDB не имеет ни одной операции или команды для выполнения "типа изменения".

Самый быстрый способ сделать это, скорее всего, будет использовать один из драйверов и внести изменения. Вы можете использовать оболочку и написать цикл for, но с точки зрения необработанной скорости другие драйверы могут быть быстрее.

Это говорит о том, что самая медленная часть процесса будет загружать все данные с диска в память, которая будет изменена, а затем сбрасывать эти данные обратно на диск. Это было бы правдой даже с помощью волшебной команды "изменить тип".

Ответ 6

Начиная с Mongo 4.2, db.collection.update() может принять конвейер агрегации, что в итоге позволяет обновить поле на основе его текущего значения:

// { field: "some text" }
db.collection.update(
  {},
  [{ $set: { field: { ["$field"] } } }],
  { multi: true }
)
// { field: [ "some text" ] }
  • Первая часть {} - это запрос на совпадение, который фильтрует, какие документы обновлять (в данном случае все документы).

  • Вторая часть [{ $set: { field: { ["$field"] } } }] представляет собой конвейер агрегации обновлений (обратите внимание на квадратные скобки, обозначающие использование конвейера агрегации). $set (псевдоним $addFields) - это новый оператор агрегирования, который в этом случае заменяет значение поля (просто заключая его в массив). Обратите внимание, как field изменяется напрямую на основе его собственного значения ($field).

  • Не забудьте { multi: true }, иначе будет обновлен только первый соответствующий документ.