Вставить несколько записей с MongoDb - PullRequest
6 голосов
/ 28 февраля 2011

Я пытаюсь заставить MongoDB сохранить несколько записей с помощью следующего запроса, в конечном итоге используя MongoMapper и драйвер Ruby Mongo.

db.foo.update({event_id: { $in: [1,2]}}, {$inc: {visit:1}}, true, true)

Это прекрасно работает, если существуют все записи, но не создает новые записи для несуществующих записей. Следующая команда имеет желаемый эффект от оболочки, но, вероятно, не идеальна для драйвера ruby.

[1,2].forEach(function(id) {db.foo.update({event_id: id}, {$inc: {visit:1}}, true, true) });

Я мог бы перебирать каждый идентификатор, который я хочу вставить из рубина, но для этого потребовалось бы посещение базы данных для каждого элемента. Есть ли способ сохранить несколько элементов из драйвера ruby ​​только за одну поездку в базу данных? Какова лучшая практика здесь? Используя mongomapper и драйвер ruby, есть ли способ отправить несколько обновлений в одном пакете, генерируя что-то вроде следующего?

db.foo.update({event_id: 1}, {$inc: {visit:1}}, true); db.foo.update({event_id: 2}, {$inc: {visit:1}}, true);

Пример данных:

Желаемые данные после команды, если существуют две записи.

{ "_id" : ObjectId("4d6babbac0d8bb8238d02099"), "event_id" : 1, "visit" : 11 }
{ "_id" : ObjectId("4d6baf56c0d8bb8238d0209a"), "event_id" : 2, "visit" : 2 }

Фактические данные после команды, если существуют две записи.

{ "_id" : ObjectId("4d6babbac0d8bb8238d02099"), "event_id" : 1, "visit" : 11 }
{ "_id" : ObjectId("4d6baf56c0d8bb8238d0209a"), "event_id" : 2, "visit" : 2 }

Желаемые данные после команды, если существует только запись с event_id 1.

{ "_id" : ObjectId("4d6babbac0d8bb8238d02099"), "event_id" : 1, "visit" : 2 }
{ "_id" : ObjectId("4d6baf56c0d8bb8238d0209a"), "event_id" : 2, "visit" : 1 }

Фактические данные после команды, если существует только запись с event_id 1.

{ "_id" : ObjectId("4d6babbac0d8bb8238d02099"), "event_id" : 1, "visit" : 2 }

Ответы [ 3 ]

2 голосов
/ 28 февраля 2011

Это - правильно - не будет вставлять никакие записи с event_id 1 или 2, если они еще не существуют

db.foo.update({event_id: { $in: [1,2]}}, {$inc: {visit:1}}, true, true)

Это потому, что часть запроса objNew (см. http://www.mongodb.org/display/DOCS/Updating#Updating-UpsertswithModifiers) не имеет значения для поля event_id. В результате вам потребуется как минимум X + 1 поездок в базу данных, где X - число event_ids, чтобы гарантировать, что вы вставите записьесли он не существует для определенного event_id (+1 прибывает из запроса выше, который увеличивает счетчик посещений для существующих записей). Чтобы сказать это по-другому, как MongoDB узнает, что вы хотите использовать значение 2 для event_idа не 1? А почему не 6?

В отношении пакетной вставки с ruby, я думаю, что это возможно, как следует из следующей ссылки - хотя я использовал только драйвер Java: Пакетная вставка / обновление с использованиемMongoid

0 голосов
/ 30 августа 2011

Я нашел способ сделать это, используя оператор eval для выполнения кода на стороне сервера.Вот фрагмент кода:

def batchpush(body, item_opts = {})
    @batch << {
        :body => body,
        :duplicate_key => item_opts[:duplicate_key] || Mongo::Dequeue.generate_duplicate_key(body),
        :priority => item_opts[:priority] || @config[:default_priority]
    }
end

def batchprocess()
    js = %Q|
        function(batch) {
            var nowutc = new Date();
            var ret = [];
            for(i in batch){
                e = batch[i];
                //ret.push(e);
                var query = {
                    'duplicate_key': e.duplicate_key,
                    'complete': false,
                    'locked_at': null
                };
                var object = {
                    '$set': {
                        'body': e.body,
                        'inserted_at': nowutc,
                        'complete': false,
                        'locked_till': null,
                        'completed_at': null,
                        'priority': e.priority,
                        'duplicate_key': e.duplicate_key,
                        'completecount': 0
                    },
                    '$inc': {'count': 1}
                };

                db.#{collection.name}.update(query, object, true);
            }
            return ret;
        }
    |
    cmd = BSON::OrderedHash.new
    cmd['$eval'] = js
    cmd['args'] = [@batch]
    cmd['nolock'] = true
    result = collection.db.command(cmd)
    @batch.clear
    #pp result
end

Несколько элементов добавляются с помощью batchpush(), а затем вызывается batchprocess().Данные отправляются в виде массива, и все команды выполняются.Этот код используется в GEM MongoDequeue, в этот файл .

. Выполнен только один запрос, и все обновления происходят на стороне сервера.

0 голосов
/ 03 марта 2011

После чего вам нужна команда Найти и изменить с опцией upsert, установленной в true.См. пример из набора тестов Mongo (тот же, на который ссылается документ Поиск и изменение ), где приведен пример, очень похожий на то, что вы описываете в своем вопросе.

...