etayluz
etayluz

Reputation: 16416

MongoDb: Insert or update multiple documents with a unique index

I have a MongoDB collection with a unique index. I am trying to insert or update an array of documents into that collection.

If there is NO existing document in the collection matching the unique index of the document, that new document should be inserted into the collection.

However, if there IS already a document in the collection with that unique index, it should be updated with the fields of the new document. Any fields that are NOT present in the new document should be left untouched.

This is what I have currently which is working for inserting (but NOT for updating).

const mongojs = require('mongojs');
const db = mongojs('mongodb://username:[email protected]:37230/database');

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

I understand this is wrong and it currently gives this error:

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

What is the proper query for this?

Upvotes: 3

Views: 8591

Answers (3)

lee shin
lee shin

Reputation: 894

You can try using 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 });

Upvotes: 5

Tyler Kirby
Tyler Kirby

Reputation: 263

I don't believe that you can update an entire array of documents at the same time. Therefore, you would have to update each item in the array individually.

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

The {upsert: true} option will update if a record exists and insert if not.

Upvotes: 4

Israel Zinc
Israel Zinc

Reputation: 2769

What are you looking for is an upsert, not an insert. It can be done by the following code:

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

Query will search for a document using the parameters of the query, if it finds, it will update the fields mentioned in . If it doesn't find, it will insert a new document with the fields and values of .

The last object (with multiple fields), contains a field to say if an upsert is desired and one called "multi" to say if an update on multiple documents is desired.

For example:

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

This will search for a document with the name "item1" and set its price to 20. If it doesn't find, it will create a new one with price 20.

One thing to be noticed though is:

If you don't use the tag $set on the fields, it will substitute the whole document.

Supposing you have a document like this:

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

If you run the following two queries:

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

and

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

it will yeld different results:

First one:

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

Second one:

{_id:"1234",price:20}

If you don't call $set, it will change the whole document.

More information on the manual:

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

Hope my answer was helpful

Upvotes: 0

Related Questions