Jankapunkt
Jankapunkt

Reputation: 8423

What is the fastest way to update the whole document (all fields) in MongoDB?

Let's say I want to update the whole document and override all fields, except _id. What of the three methods is the best in terms of resource consumption:

1. Set the complete document as update parameter, so all fields are passed

Example:

collection.update({_id: docId}, {$set:updateDoc});

2. Calculate a delta document between the original and the updateDoc

Example:

const originalDoc = collection.findOne(docId);
const deltaDoc = calculateDeltaFct(originalDoc, updateDoc); //get changed fields
collection.update({_id: docId}, {$set:deltaDoc});

3. Use the Mongo 3.2. replaceOne function

Example:

collection.replaceOne({_id: docId}, {$set:updateDoc});

I have an assumption of the pros and the cons of each methods but I want to be sure what to choose and why. I am not sure how to measure it precisely, so maybe someone can help.

Background:

I have a metrics collection where many documents are updated often, but the fields to be updated vary a lot, so it is hard to write an update method for each field. Instead I intend to just throw all data in and update all fields, so I keep my code clean with only one update method for all updates.

Update:

In my setup, there are no subdocuments embedded in the document structure. I also have no sharding and replication in my (dev) setup.

Furthermore I found some method (collection.explain) which I will use to research on that topic, too. Nevertheless, any help or hint is much appreciated.

Upvotes: 4

Views: 3108

Answers (2)

amota
amota

Reputation: 331

I'm not sure if this is the "fastest" way, but this is one method of updating the whole document "except _id", paying special attention to the part about "fields to be updated vary a lot".

Note: this example assumes your "updateDoc" has the _id field included in it.


I wanted to update all fields without having to actually explicitly state them.

My situation:

Attempted update of all document fields:

await examCollection.findOneAndUpdate(
  {_id: new ObjectID(this.examId)},
  {$set: this.data}
)

...except, this.data happened to have _id in it as well, which I didn't want to update. (In fact, it gave me an error, because _id is immutable.)

So, for my workaround, I ended up "deleting" all fields on the object that I didn't want to update (i.e. _id).

Successful update of all document fields, except specified ones:

// (1) specify fields that I don't want updated (aka get rid of them from object)
delete this.data._id 
//delete this.data.anotherField
//delete this.data.anotherField2
//delete this.data.anotherField3
    
// (2) update MongoDB document
await examCollection.findOneAndUpdate(
  {_id: new ObjectID(this.examId)},
  {$set: this.data}
)

This was much easier than explicitly stating all the fields that I did want to update, because there were A LOT, and they could potentially change in the future (new fields added, fields deleted, etc.).

Hopefully this strategy can help!

Note: In reality, I did my "field specifying" earlier in another file, rather than immediately before updating like it shows in the example, but same effect.

Upvotes: 0

twg
twg

Reputation: 1105

It really depends if you require the old information before the update. If you are overwriting the info and even for one key - > value pair then I would use either update or replaceOne. The difference may be in time depending on the size of your collection (dataset). If that is of concern benchmark the difference. Personally I would lean towards replaceOne, but that is just based on experience and the collections I deal with.

For what you have explained I don't think your second choice is either efficient or being memory savvy. It does not sound like you need such a calculation for simply updating data where there is no concern over overwriting previous information.

Upvotes: 1

Related Questions