Изменение типа 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 }
, иначе будет обновлен только первый соответствующий документ.