Search code examples
node.jsmongodbmongoosenosqlmongodb-query

MongoDB: Set field value to 10 if less than 10, otherwise increment by one


Consider the following code:

findAndModify({id: id}, undefined, {$inc: {counter: 1}, {$max: {counter: 10})

This fails with an error because both $inc and $max try to update the same field.

But what if I want to set the counter to 10 if its value is less than 10 and if not, increment its value by 1? How do I do that in one atomic operation?

Is there a way to apply the updates sequentially in a single operation?


Solution

  • I don't think that can be done in a single operation. However, you can create an aggregate query with the conditional statements that you then use in your update.

    (async () => {
        try {
            const results = await Model.aggregate([
                { '$match': { 'id': id } },
                { '$project': { 
                    'counter': { 
                        '$cond': [
                            { '$lt': ['$counter', 10 ] },
                            10,
                            { '$add': ['$counter', 1 ] }
                        ] 
                    }
                } }
            ]).exec();
    
            const data = results[0];
            const { counter } = data;
    
            const doc = await Model.findOneAndUpdate({ id },
                { '$set': { counter } },
                { new: true }
            ).exec();
    
            console.log(doc);
        } 
        catch (err) {
            console.error(err);
        }
    })()
    

    For an atomic update, include a query that restricts the increment for documents that only have counter less than the given ceiling value of 10:

    findAndModify(
        {
            'id': id,
            'counter': { '$lt': 10 } 
        }, undefined, 
        { '$inc': { 'counter': 1 } },
        callback
    )