MongoDb: 插入或更新具有唯一索引的多个文档

MongoDb: Insert or update multiple documents with a unique index

我有一个带有唯一索引的 MongoDB 集合。 我正在尝试将一组文档插入或更新到该集合中。

如果集合中没有与文档的唯一索引匹配的现有文档,则应将该新文档插入到集合中。

但是,如果集合中已经存在具有该唯一索引的文档,则应使用新文档的字段对其进行更新。新文档中不存在的任何字段都应保持不变。

这是我目前拥有的用于插入(但不用于更新)的内容。

const mongojs = require('mongojs');
const db = mongojs('mongodb://username:password@address.mlab.com:37230/database');

             // items is an array of documents
db.items.insert(items, (err, task) => {
    if (err) {
      console.log(err);
    }
  })

我知道这是错误的,目前它给出了这个错误:

E11000 duplicate key error index: database.items.$upc_1 dup key:

对此的正确查询是什么?

您要查找的是更新插入,而不是插入。可以通过以下代码完成:

db.collection.update(
   <query>,
   <updates>,
   {
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>,
     collation: <document>
   }
)

查询将使用查询的参数搜索文档,如果找到,它将更新中提到的字段。如果没有找到,它将插入一个新文档,其中包含 的字段和值。

最后一个对象(具有多个字段)包含一个字段,用于说明是否需要更新插入,还有一个名为 "multi" 的字段用于说明是否需要对多个文档进行更新。

例如:

db.items.update({name:"item1"},{$set:{price:20}},{upsert:true}) 

这将搜索名称为 "item1" 的文档并将其价格设置为 20。如果找不到,它将创建一个价格为 20 的新文档。

不过要注意的一件事是:

如果您不在字段上使用标记 $set,它将替换整个文档。

假设您有这样的文档:

{_id:"1234",name:"item1",price:10}

如果你运行以下两个查询:

db.items.update({name:"item1"},{$set:{price:20}},...)

db.items.update({name:"item1"},{price:20},...)

它会产生不同的结果:

第一个:

{_id:"1234",name:"item1",price:20}

第二个:

{_id:"1234",price:20}

如果你不调用$set,它会改变整个文档。

有关手册的更多信息:

https://docs.mongodb.com/manual/reference/method/db.collection.update/

希望我的回答对您有所帮助

我不相信您可以同时更新整个文档数组。因此,您必须单独更新数组中的每个项目。

items.forEach((item) => {
   db.items.update({_id: item._id}, item, {upsert: true}, (err, task) => {
           if (err) {
             console.log(err);
           }
   });
}

{upsert: true} 选项将在记录存在时更新,否则插入。

您可以尝试使用 mongodb bulkWrite api:

var ops = []

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

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