Tri Nguyen
Tri Nguyen

Reputation: 99

MongoDB - how to only update field if field does not exist

How can I update a mongo document with the following requirements:

Find a document by email property:

If the document exists:

  1. If both retrieved and new document have property A, keep property A (the retrieved one).
  2. If retrieved document property A is null or undefined or doesn't exist, update using property A of the new object.

If the document doesn't exist

  1. Insert the new document.

The findOneAndUpdate seems not to convey the both 3 of the requirements. Thanks.

Upvotes: 1

Views: 14695

Answers (3)

Ronak Khunt
Ronak Khunt

Reputation: 1

await Order.updateOne({ _id: item._id }, { $set: { orderNumber: generateRandomNumber(12) }}, { upsert: true });

You can do like this.

Upvotes: 0

Aleksandar Cvetojevic
Aleksandar Cvetojevic

Reputation: 386

My recommendation is to go the following path:

db.getCollection('<some-collection>').update(
    { email: '[email protected]' },
    {
        $set: {
            name: "some guy",
            username: someguy,
            tel: '1234'
        }
    },
    { upsert: true }
);

Check upsert documentation: https://docs.mongodb.com/manual/reference/method/db.collection.update/#upsert-option

Lets go through your requirements now:

3. If the document doesn't exist, insert the new document.

Yes, it will insert new document to collection if it doesnt find the document by email. Resulting document will be combination of find condition + $set + autogenerated _id, so it will look something like this:

{
    _id: ObjectId(...)
    email: '[email protected]'
    name: "some guy",
    username: someguy,
    tel: '1234'
}

2. If retrieved document property A is null or undefined or doesn't exist, update using property A of the new object.

All properties provided in $set will unconditionally be persisted in the database, which also covers your requirement of updating null/undefined values

3. If both retrieved and new document have property A, keep property A (the retrieved one).

If both newly provided A and database A are the same, we dont have a problem. If As are different, dont you want to store the new A value? If you are afraid of nulls/undefined values, you can omit them before providing object to $set. What is the use-case for you not wanting to update database property with newly provided value? One use-case i can see is that you want to pass createdAt in case you are creating new record, but dont want to update that value for existing records. If thats the case, and you know those properties in advance, you can use $setOnInsert update operator. https://docs.mongodb.com/manual/reference/operator/update/#id1

So your update query can look like this:

db.getCollection('<some-collection>').update(
    { email: '[email protected]' },
    {
        $set: {
            name: "some guy",
            username: someguy,
            tel: '1234'
        },
        $setOnInsert: {
            createdAt: new Date(),
            updatedAt: new Date()
        }
    },
    { upsert: true }
);

I hope this helps!

Upvotes: 12

vizsatiz
vizsatiz

Reputation: 2173

You need not retrieve the document for updating the property A. You can use the update API of mongo to do so. Please find the psuedo code below:

db.<collection>.update({
    "$or": [
        { "PropertyA": { "$exists": false } }, 
        { "PropertyA": null }
    ]
}, {$set: {"PropertyA": "NewValue"}});

The above code is for one property, but I think you can figure out how to scale it up.

Hope this helps !!

Upvotes: 3

Related Questions