在MongoDB中插入或更新许多文档

时间:2016-10-25 16:07:23

标签: 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,
   }
)

如果出现重复,该查询将发出一个writeErrors,其中包含一个对象数组,其中包含无法插入的文档的索引。我可以通过它们来更新它们。

但这个过程很麻烦。有没有办法在一个查询中插入或更新/替换许多文档?

3 个答案:

答案 0 :(得分:6)

正如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次的操作。 mongo shell中的Bulk()操作和驱动程序中的类似方法没有此限制。

source

答案 1 :(得分:1)

考虑如下数据项:

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;
        }
    }

答案 2 :(得分:1)

您还可以使用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 });