2016-02-04 3 views
3

Я хочу обновить несколько документов разными значениями.Mongoose multi update

Моя база данных выглядит примерно так.

[ 
    { 
     "_id": 1, 
     "value": 50 
    }, 
    { 
     "_id": 2, 
     "value": 100 
    } 
] 

Этот запрос возвращает ошибку, потому что я передаю массив вместо объекта в $ set.

Model.update({_id: {$in: ids}}, {$set: ids.value}, {multi: true}; 

Я хочу, чтобы моя база данных, чтобы выглядеть следующим образом

[ 
     { 
      "_id": 1, 
      "value": 4 
     }, 
     { 
      "_id": 2, 
      "value": 27 
     } 
    ] 

ответ

3

Прежде всего вашего update() запроса не работает.

См. документацию по данному вопросу here

Model.update(conditions, update, options, callback);

Предположим, что текущая модель БД содержит документы, как это (как описано в вопросе, а):

[ 
    { 
     "_id": 1, 
     "value": 50 
    }, 
    { 
     "_id": 2, 
     "value": 100 
    } 
]; 

и вы имеете ниже массив, который содержит объекты (т.е., Документы) должны быть изменены с Документами текущих децибел нравится это:

idsArray: [ 
    { 
     "_id": 1, 
     "value": 4 
    }, 
    { 
     "_id": 2, 
     "value": 27 
    } 
]; 

Из моего опыта работы с MongoDB & мангустом, я не думаю, что вы можете обновить все документы с однолинейным запросом (что вы пытаетесь делать) .. (PS Я не знаю об этом, так что я не уверен в этом ..)

Но, чтобы сделать ваш код работать, вы будете делать что-то вроде этого:

Идея: Цикл по каждый документ в документах, т. е. idsArray, и вызывают обновление() над ним.

Итак, вот код этого:

idsArray.forEach(function(obj) { 
    Model.update({_id: obj._id}, {$set: {value: obj.value}}); 
}); 

В коде выше, я предположим, вы имеете _id значения в БД документы, как они «повторно написано выше (то есть, "_id": 1) .. Но если они, как это "_id": ObjectId('1')

[ 
    { 
    "_id": ObjectId('1'), 
    "value": 50 
    }, 
    ..... 
    ..... 
] 

тогда вам будет нужно конвертировать _id в ObjectId(obj._id) в обновлении() запрос .. так для этого вы будете делать, как это.

var ObjectId = require('mongodb').ObjectID; 

idsArray.forEach(function(obj) { 
    Model.update({_id: ObjectId(obj._id)}, {$set: {value: obj.value}}); 
}); 

P.S. Просто подтвердите это (то есть, _id), прежде чем идти вперед ..

Надеюсь, это поможет.

Cheers,

+0

Я пробовал раньше что-то подобное, где я петлю через свои значения. Мой вопрос, если я возьму этот метод, где я устанавливаю свой res.end(); потому что, если я установлю свой res.end() после завершения foreach, у меня все еще есть куча обратных вызовов, ожидающих завершения моего Model.update. – user3862830

+0

через callback (я думаю) - попробуйте сделать функцию func 'callback (callback) {callback();}', которая обновляет все документы в db и возвращает обратный вызов в главную функцию, где вы будете выполнять свою работу; просто попробуйте этот путь. – narainsagar

+0

функция (скажем: 'callbackFunc'), которая будет обновлять все ваши документы, а затем возвращать обратный вызов туда, откуда она была вызвана (предположим:' mainFunc'), поэтому это означает, что все ваши документы будут обновлены (означает, что callbackFunc завершает), то вы будете делать/вызывать 'res.end()' – narainsagar

1

Мульти обновление может использоваться только для обновления нескольких документов на ту же величину (ы) или обновление с той же update operation для всех документов.

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

6

предположив, что вы имели массив объектов, которые вы хотели обновить в вашей коллекции на соответствующих идентификаторам как

var soldItems = [ 
     { 
      "_id": 1, 
      "value": 4 
     }, 
     { 
      "_id": 2, 
      "value": 27 
     } 
    ]; 

, то вы можете использовать метод forEach() на массив для перебора его и обновить свою коллекцию:

soldItems.forEach(function(item)){ 
    Model.update({"_id": item._id}, {"$set": {"value": item.value }}, callback); 
}); 

или использовать обещания как

var updates = []; 
soldItems.forEach(function(item)){ 
    var updatePromise = Model.update({"_id": item._id}, {"$set": {"value": item.value }}); 
    updates.push(updatePromise); 
}); 

Promise.all(updates).then(function(results){ 
    console.log(results); 
}); 

или с помощью map()

var updates = soldItems.map(function(item)){ 
    return Model.update({"_id": item._id}, {"$set": {"value": item.value }});  
}); 

Promise.all(updates).then(function(results){ 
    console.log(results); 
}); 

Для больших массивов, вы можете воспользоваться помощью насыпной записи API для повышения производительности. Для версий Mongoose >=4.3.0, которые поддерживают MongoDB Server 3.2.x, вы можете использовать bulkWrite() для уточнений. Следующий пример показывает, как вы можете об этом:

var bulkUpdateCallback = function(err, r){ 
    console.log(r.matchedCount); 
    console.log(r.modifiedCount); 
} 
// Initialise the bulk operations array 
var bulkOps = soldItems.map(function (item) { 
    return { 
     "updateOne": { 
      "filter": { "_id": item._id } ,    
      "update": { "$set": { "value": item.value } } 
     }   
    }  
}); 

// Get the underlying collection via the native node.js driver collection object 
Model.collection.bulkWrite(bulkOps, { "ordered": true, w: 1 }, bulkUpdateCallback); 

Для Mongoose версий ~3.8.8, ~3.8.22, 4.x, которые поддерживают MongoDB сервер >=2.6.x, вы могли бы использовать Bulk API следующим

var bulk = Model.collection.initializeOrderedBulkOp(), 
    counter = 0; 

soldItems.forEach(function(item) { 
    bulk.find({ "_id": item._id }).updateOne({ 
     "$set": { "value": item.value } 
    }); 

    counter++; 
    if (counter % 500 == 0) { 
     bulk.execute(function(err, r) { 
      // do something with the result 
      bulk = Model.collection.initializeOrderedBulkOp(); 
      counter = 0; 
     }); 
    } 
}); 

// Catch any docs in the queue under or over the 500's 
if (counter > 0) { 
    bulk.execute(function(err,result) { 
     // do something with the result here 
    }); 
} 
Смежные вопросы