Обновите коллекцию MongoDB, используя $toLower
У меня есть существующая коллекция MongoDB, содержащая имена пользователей. Имена пользователей содержат как строчные, так и прописные буквы.
Я хочу обновить все имена пользователей, чтобы они содержали только строчные буквы.
Я пробовал этот скрипт, но он не работал
db.myCollection.find().forEach(
function(e) {
e.UserName = $toLower(e.UserName);
db.myCollection.save(e);
}
)
Ответы
Ответ 1
MongoDB не имеет понятия $toLower
в качестве команды. Решение состоит в том, чтобы запустить большой цикл for
по данным и выдавать обновления по отдельности.
Вы можете сделать это в любом драйвере или из оболочки:
db.myCollection.find().forEach(
function(e) {
e.UserName = e.UserName.toLowerCase();
db.myCollection.save(e);
}
)
Вы также можете заменить сохранение на атомное обновление:
db.myCollection.update({_id: e._id}, {$set: {UserName: e.UserName.toLowerCase() } })
Опять же, вы также можете сделать это от любого из драйверов, код будет очень похож.
РЕДАКТОР: Ремон поднимает хороший момент. Команда $toLower
существует как часть структуры агрегации, но это не имеет ничего общего с обновлением. Документация для обновления здесь.
Ответ 2
Очень похожее решение, но это сработало в новом mongo 3.2
Выполните следующие действия в Mongo Shell или аналогичных инструментах DB, таких как MongoChef!
db.tag.find({hashtag :{ $exists:true}}).forEach(
function(e) {
e.hashtag = e.hashtag.toLowerCase();
db.tag.save(e);
});
Ответ 3
Просто заметьте, чтобы убедиться, что поле существует для всех записей в вашей коллекции. Если нет, вам понадобится инструкция if, например:
if (e.UserName) e.UserName = e.UserName.toLowerCase();
Ответ 4
С принятым решением я знаю, что его очень тривиально делать то же самое для массива элементов, на всякий случай
db.myCollection.find().forEach(
function(e) {
for(var i = 0; i < e.articles.length; i++) {
e.articles[i] = e.articles[i].toLowerCase();
}
db.myCollection.save(e);
}
)
Ответ 5
Немного опоздал на вечеринку, но приведенный ниже ответ очень хорошо работает с mongo 3.4 и выше. Сначала получите только те записи, которые имеют другой регистр, и обновите только эти записи оптом. Производительность этого запроса в несколько раз лучше
var bulk = db.myCollection.initializeUnorderedBulkOp();
var count = 0
db.myCollection.find({userId:{$regex:'.*[A-Z]'}}).forEach(function(e) {
var newId = e.userId.toLowerCase();
bulk.find({_id:e._id}).updateOne({$set:{userId: newId}})
count++
if (count % 500 === 0) {
bulk.execute();
bulk = db.myCollection.initializeUnorderedBulkOp();
count = 0;
}
})
if (count > 0) bulk.execute();
Ответ 6
Начиная с Mongo 4.2
, db.collection.update()
может принять конвейер агрегации, что в конечном итоге позволяет обновить поле на основе его собственного значения:
// { username: "Hello World" }
db.collection.update(
{},
[{ $set: { username: { $toLower: "$username" } } }],
{ multi: true }
)
// { username: "hello world" }
-
Первая часть {}
- это запрос на совпадение, который фильтрует, какие документы обновлять (в данном случае все документы).
-
Вторая часть [{ $set: { username: { $toLower: "$username" } } }],
- это конвейер агрегации обновлений (обратите внимание на квадратные скобки, обозначающие использование конвейера агрегации):
-
$set
- это новый оператор агрегирования, который в этом случае изменяет значение для "username"
. - Используя
$toLower
, мы модифицируем значение "username"
его строчной версией.
-
Не забудьте { multi: true }
, иначе будет обновлен только первый соответствующий документ.