Подтвердить что ты не робот

Обновите коллекцию MongoDB, используя $toLower

У меня есть существующая коллекция MongoDB, содержащая имена пользователей. Имена пользователей содержат как строчные, так и прописные буквы.

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

Я пробовал этот скрипт, но он не работал

db.myCollection.find().forEach(
 function(e) {
 e.UserName = $toLower(e.UserName);
 db.myCollection.save(e);
 }
)
4b9b3361

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