2016-12-10 3 views
1

В MongoDB, я ищу способ ATOMICally обновить несколько документов и вернуть все обновленные документы за один раз.ATOMICally обновить несколько документов И вернуть их

Мы можем сделать все следующие в MongoDB:

  • атомарных обновить один документ и вернуть обновленный документ: findAndModify или findOneAndUpdate
  • атомарных обновить несколько документов: update(...{multi: true} или updateMany
  • запроса и возврат несколько документов: find

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

ответ

1

Atomically update multiple documents: update(...{multi: true} or updateMany

Unfourtantely, что является ложным:

In MongoDB, write operations, e.g. db.collection.update(), db.collection.findAndModify(), db.collection.remove(), are atomic on the level of a single document.


In MongoDB, a write operation is atomic on the level of a single document, even if the operation modifies multiple embedded documents within a single document.

Однако, вы можете моделировать транзакции атомарно обновления нескольких документов по "using a two-phase commit approach", который подробно описан здесь.

Вы также можете посмотреть на $isolated оператора, "prevents a write operation that affects multiple documents from yielding to other reads or writes once the first document is written" но "does not provide “all-or-nothing” atomicity for write operations"

В целом, это не возможно на уровне MongoDB (ни водителя), но вы можете имитировать его на своем уровне приложений, следовательно, обратный что вам нужно.

+0

Спасибо за хедз-апе на атомном уровне. Основываясь на супер полезных ссылках, которые вы отправили, я думаю, что оператор $ изолированных будет предоставлять то, что мне нужно в этом случае для обновления. Подход на основе timetamp, подобный двухфазному фиксации, который вы упомянули, должен работать, чтобы гарантировать, что документы, которые я возвращаю, такие же, как те, которые были только что обновлены. –

0

Я проверил updateMany.

Testing1:

Update 40K документы с updateMany (тянуть), во время выполнения, выключение DB внезапно, то некоторые узлы прошли (данные вытянута), некоторые не смогли (данные не тянули в каком-то уровне 5 узлов в дереве), перезапустите db и снова запустите updateMany, все переданы и все данные верны.

Испытание 2:

Создать уникальный индекс на поле, вставить некоторые данные, в методе updateMany, некоторые документы не удалось из-за уникальным ключ нарушения.

Результаты моего теста2: обновлен нулевой документ.


function insertData() { 
    const dataSource = app.models.Entity.getDataSource(); 
    return new Promise((resolve, reject) => { 
    dataSource.connector.connect((err, db) => { 
     if (err) { 
     reject(new Error('.... error')); 
     return; 
     } 
     const entityCollection = db.collection('Entity'); 
     // Create index 
     entityCollection.createIndex({ age: 1 }, { unique: true }) 
     .then(() => { 
     // Insert data 
     const data = [ 
      { 
      id: uuid.v4(), 
      age: 1, 
      type: 'test', 
      }, 
      { 
      id: uuid.v4(), 
      age: 2, 
      type: 'test', 
      }, 
      { 
      id: uuid.v4(), 
      age: 3, 
      type: 'test', 
      }, 
      { 
      id: uuid.v4(), 
      age: 4, 
      type: 'test', 
      }, 
      { 
      id: uuid.v4(), 
      age: 5, 
      type: 'test', 
      }, 
      { 
      id: uuid.v4(), 
      age: 6, 
      type: 'test', 
      }, 
     ]; 
     return insertData(data); 
     }) 
     .then(() => { 
     resolve(); 
     }) 
     .catch((err2) => { 
     reject(err2); 
     }); 
    }); 
    }); 
} 

function updateAge() { 
    const dataSource = app.models.Entity.getDataSource(); 
    return new Promise((resolve, reject) => { 
    dataSource.connector.connect((err, db) => { 
     if (err) { 
     reject(new Error('...error')); 
     return; 
     } 
     const entityCollection = db.collection('Entity'); 
     entityCollection.updateMany(
     { age: { $gt: 0 } }, 
     { $mul: { age: 2 } }, 
    ).then(() => { 
     resolve(); 
     }) 
     .catch((err2) => { 
     logger.error(`ERROR is ${err2}`); 
     reject(err2); 
     }); 
    }); 
    }); 
} 

Результат теста: Нулевой документы обновляются. "msg": "ОШИБКА - это MongoError: E11000 копия коллекции ошибок: контент-база.Индекс Entity: age_1 DUP ключ: {: 2}», "V": 1} 1) тест updateMany

0 прохождение (114ms) 1 неудачу