2016-10-25 3 views
3

Есть ли способ вставить или обновить/заменить несколько документов в MongoDB одним запросом?Вставить или обновить многие документы в MongoDB

Предположим следующую коллекцию:

[ 
    {_id: 1, text: "something"}, 
    {_id: 4, text: "baz"} 
] 

Теперь я хотел бы добавить несколько документов, некоторые из которых, возможно, уже в коллекции. Если документы уже находятся в коллекции, я бы хотел их обновить или заменить. Например, я хотел бы включить следующие документы:

[ 
    {_id:1, text: "something else"}, 
    {_id:2, text: "foo"}, 
    {_id:3, text: "bar"} 
] 

Запрос должен вставить документы с _id 2 и 3. Необходимо также обновить/заменить документ с _id 1. После процесса, коллекция должна выглядеть следующим образом:

[ 
    {_id:1, text: "something else"}, 
    {_id:2, text: "foo"}, 
    {_id:3, text: "bar"}, 
    {_id:4, text: "baz"} 
] 

Один из подходов может быть использование insertMany:

db.collection.insertMany(
    [ {...}, {...}, {...} ], 
    { 
     ordered: false, 
    } 
) 

If Дублировать es, этот запрос будет генерировать writeErrors, содержащий массив объектов, содержащих индексы документов, которые не были вставлены. Я мог бы пройти через них и обновить их.

Но этот процесс громоздкий. Есть ли способ вставить или обновить/заменить многие документы в один вопрос?

ответ

4

Как сказал here, чтобы делать то, что вам нужно вы можете положить что-то подобное в

script.js

(* предупреждение: непроверенный код)

use YOUR_DB 
var bulk = db.collection.initializeUnorderedBulkOp(); 
bulk.find({ _id : 1 }).upsert().update({ $set: { "text": "something else" } }); 
bulk.find({ _id : 4 }).upsert().update({ $set: { "text": "baz" } }); 
bulk.find({ _id : 99 }).upsert().update({ $set: { "text": "mrga" } }); 
bulk.execute(); 

и запустить с

mongo < script.js

Я должен был сделать это так, как все, что я пробовал для обновления/вставки более 1000 документов, не работал из-за ограничения.

Команды записи могут принимать не более 1000 операций. Операции Bulk() в оболочке mongo и сопоставимые методы в драйверах не имеют этого предела.

source

+0

Великого. Спасибо :) – str

0

Учитывая элемент данных следующим образом:

interface Item { 
    id: string;   // unique key across collection 
    someValue: string; 
} 

Если у вас есть элементы под лимит 1000, вы можете сделать объемную операцию записи, как это:

public async insertOrUpdateBulk(items: Item[]) { 
     try { 
      const bulkOperation = this._itemCollection.initializeUnorderedBulkOp(); 
      for (let itemIndex = 0; itemIndex < items.length; itemIndex++) { 
       const item = items[itemIndex]; 
       bulkOperation.find({ id: item.id }).upsert().update(item); 
      } 
      await bulkOperation.execute(); 
      return true; 
     } catch (err) { 
      console.log(err); 
      return false; 
     } 
    } 

Если у вас есть предметы, превышающие предел 1000, вы можете делать одновременные обещания:

public async insertOrUpdate(items: Item[]) { 
     try { 
      const promises: Array<Promise<UpdateWriteOpResult>> = []; 
      for (let itemIndex = 0; itemIndex < items.length; itemIndex++) { 
       const item = items[itemIndex]; 
       const updatePromise = this.itemCollection.updateOne({ id: item.id }, item, { upsert: true }); 
       promises.push(updatePromise); 
      } 
      await Promise.all(promises); 
      console.log('done...'); 
      return true; 
     } catch (err) { 
      console.log(err); 
      return false; 
     } 
    } 
0

Вы также можете использовать bulkWrite API для обновления или вставки нескольких документов в одном запросе, здесь приведен пример

var ops = [] 

items.forEach(item => { 
    ops.push(
     { 
      updateOne: { 
       filter: { _id: unique_id }, 
       update: { 
        $set: { fields_to_update_if_exists }, 
        $setOnInsert: { fileds_to_insert_if_does_not_exist } 
       }, 
       upsert: true 
      } 
     } 
    ) 
}) 

db.collections('collection_name').bulkWrite(ops, { ordered: false });