Java, MongoDB: как обновить каждый объект при повторении огромной коллекции?

У меня есть коллекция около 1 миллиона записей с 20 полями в каждой. Мне нужно обновить целочисленное поле flag в каждой записи (документе), случайным образом назначив 1 или 2 этому полю flag. Как это сделать при итерации курсора по всей коллекции? Не кажется хорошей идеей второй раз искать объект, уже найденный MongoDB, только для того, чтобы иметь возможность его обновить:

  DBCursor cursor = coll.find();
  try {
     while(cursor.hasNext()) {
    BasicDBObject obj = (BasicDBObject) cursor.next();
    ...
    coll.update(query,newObj)

     }
  } finally {
     cursor.close();
  }

Как эффективно обновлять поле в каждом документе огромной коллекции MongoDB с разными значениями?


person Anton Ashanin    schedule 12.04.2013    source источник
comment
Вы можете обновить все документы (соответствующие определенному условию) в одном запросе, установив флаг «несколько» в команде «обновить» в значение «истина». Проверьте это: stackoverflow.com/questions/4146452/   -  person Aafreen Sheikh    schedule 12.04.2013
comment
Я не могу использовать флаг multi, потому что я обновляю каждый документ уникальным значением. Это не то же самое, что обновлять множество документов одним и тем же значением.   -  person Anton Ashanin    schedule 12.04.2013
comment
https://stackoverflow.com/questions/4146452/mongodb-what-is-the-fastest-way-to-update-all-records-in-a-collection/50768815#50768815 Я ответил там. Надеюсь, поможет.   -  person shijin    schedule 09.06.2018


Ответы (2)


Ваш подход в принципе правильный. Однако я бы не считал такую ​​коллекцию «огромной». Вы можете запустить что-то подобное из оболочки:

coll.find({}).forEach(function (doc) {
    doc.flag = Math.floor((Math.random()*2)+1);
    coll.save(doc);
 });

В зависимости от вашей версии, конфигурации и нагрузки MongoDB это может занять от нескольких минут до нескольких часов.

Если вы хотите выполнить массовое обновление, используйте некоторые условия в документе запроса, например coll.find({"aFiled" : {$gt : minVal}, "aFiled" : {$lt : maxVal}}).

person Ori Dar    schedule 12.04.2013
comment
В моем подходе MongoDB просматривает каждый документ дважды. Имеет ли это смысл? - person Anton Ashanin; 12.04.2013
comment
Моя исправленная функция сводит ее к одному запросу курсора, вы не делаете дополнительный запрос за итерацию. Как видите, я использую coll.save(doc) - person Ori Dar; 12.04.2013
comment
У этого есть проблемы: см. docs.mongodb.org/manual/ часто задаваемые вопросы/разработчики/ - person Nashenas; 06.05.2015
comment
Не забудьте добавить noCursorTimeout(), если вы работаете с огромной коллекцией! В противном случае время ожидания команды истечет через 10 минут (по крайней мере, для меня). Таким образом, верхняя строка ответа Ори становится такой: coll.find({}).noCursorTimeout().forEach(function (doc) { - person ; 09.05.2016

Мое решение моего собственного вопроса, вдохновленное @orid:

public void tagAll(int min, int max) {
    int rnd = 0;
    DBCursor cursor = this.dataColl.find();
    try {
        while (cursor.hasNext()) {
            BasicDBObject obj = (BasicDBObject) cursor.next();
            rnd = min + (int) (Math.random() * ((max - min) + 1));
            obj.put("tag", rnd);
            this.dataColl.save(obj);
        }
    } finally {
        cursor.close();
    }
}
person Anton Ashanin    schedule 13.04.2013