incrementOne is a convenience method for atomically incrementing or decrementing a field value in a single document, simplifying the use of updateOne({ $inc }).
Traditional way (using updateOne):
//❌ Need to build $inc update object
await collection('users').updateOne(
{ userId: 'user123' },
{ $inc: { loginCount: 1 } }
);Use incrementOne:
//✅ More concise and intuitive
await collection('users').incrementOne(
{ userId: 'user123' },
'loginCount'
);| Advantages | Description |
|---|---|
| Atomic operations | Concurrency safety, no race conditions |
| Code simplicity | Reduce boilerplate code by 60% |
| Intuitive and easy to read | Clear semantics |
| return result | optionally return the document before/after update |
async incrementOne(
filter: Object,
field: string | Object,
increment?: number,
options?: {
returnDocument?: 'before' | 'after',
projection?: Object,
maxTimeMS?: number,
comment?: string
}
): Promise<IncrementOneResult>
interface IncrementOneResult {
acknowledged: boolean;
matchedCount: number;
modifiedCount: number;
value: Document | null; //Document after (or before) update
}| Parameters | Type | Required | Description |
|---|---|---|---|
filter |
Object | ✅ | Query conditions |
field |
string | Object | ✅ | Field name (single field) or field-increment object (multiple fields) |
increment |
number | ❌ | Increment (default 1, negative number means decrease) |
options |
Object | ❌ | Operation Options |
options.returnDocument |
string | ❌ | Return timing ('before' | 'after', default 'after') |
options.projection |
Object | ❌ | Field Projection |
options.maxTimeMS |
number | ❌ | Operation timeout (milliseconds) |
options.comment |
string | ❌ | Query comments |
await collection('users').incrementOne(
{ userId: 'user123' },
'loginCount'
);
//loginCount increments by 1await collection('users').incrementOne(
{ userId: 'user123' },
'points',
50
);
//points increased by 50await collection('users').incrementOne(
{ userId: 'user123' },
'credits',
-30
);
//credits reduced by 30await collection('users').incrementOne(
{ userId: 'user123' },
{
loginCount: 1, // +1
points: 20, // +20
credits: -10 // -10
}
);const result = await collection('users').incrementOne(
{ userId: 'user123' },
'points',
50
);
console.log(result.value.points); //updated valueasync function recordLogin(userId) {
const result = await collection('users').incrementOne(
{ userId },
'loginCount'
);
console.log(`Number of user logins: ${result.value.loginCount}`);
return result;
}//Complete tasks and earn points
async function earnPoints(userId, points) {
const result = await collection('users').incrementOne(
{ userId },
'points',
points
);
console.log(`Current points: ${result.value.points}`);
return result;
}
//Redeem goods and deduct points
async function spendPoints(userId, points) {
const result = await collection('users').incrementOne(
{ userId },
'points',
-points
);
if (result.value.points < 0) {
throw new Error('Not enough points');
}
return result;
}async function incrementViews(articleId) {
await collection('articles').incrementOne(
{ articleId },
'views'
);
}//Restock
async function addStock(productId, quantity) {
const result = await collection('products').incrementOne(
{ productId },
'stock',
quantity
);
return result.value.stock;
}
//Ship
async function reduceStock(productId, quantity) {
const result = await collection('products').incrementOne(
{ productId },
'stock',
-quantity,
{ returnDocument: 'before' }
);
//Check if there is enough stock
if (result.value.stock < quantity) {
throw new Error('Insufficient stock');
}
return result;
}async function recordArticleInteraction(articleId, action) {
const increments = {};
if (action === 'view') increments.views = 1;
if (action === 'like') increments.likes = 1;
if (action === 'share') increments.shares = 1;
await collection('articles').incrementOne(
{ articleId },
increments
);
}//Return updated document (default)
const result = await collection('users').incrementOne(
{ userId: 'user123' },
'count',
5,
{ returnDocument: 'after' }
);
console.log(result.value.count); // 15
//Return to the document before update
const result2 = await collection('users').incrementOne(
{ userId: 'user123' },
'count',
5,
{ returnDocument: 'before' }
);
console.log(result2.value.count); //10 (value before update)const result = await collection('users').incrementOne(
{ userId: 'user123' },
'points',
50,
{ projection: { points: 1, name: 1 } }
);
//Only return _id, points, name fieldsincrementOne uses MongoDB’s $inc operator to ensure atomicity:
- ✅ Concurrency safety
- ✅ No race conditions
- ✅ No transactions required
| Method | Operation steps | Concurrency safety | Performance |
|---|---|---|---|
| incrementOne | 1 step (atomic) | ✅ | ⭐⭐⭐⭐⭐ |
| find + update | 2 steps (non-atomic) | ❌ | ⭐⭐⭐ |
| Error type | Error code | Trigger condition |
|---|---|---|
| Parameter error | INVALID_ARGUMENT |
filter/field/increment is invalid |
| Timeout Error | QUERY_TIMEOUT |
Exceeded maxTimeMS |
try {
const result = await collection('users').incrementOne(
{ userId: 'user123' },
'points',
50
);
if (result.matchedCount === 0) {
console.log('User does not exist');
}
} catch (error) {
if (error.code === 'INVALID_ARGUMENT') {
console.error('Parameter error:', error.message);
} else {
console.error('Unknown error:', error);
}
}-
Use incrementOne instead of find + update
//✅ Recommended: Atomic operations await collection('users').incrementOne( { userId: 'user123' }, 'count', 1 ); //❌ Avoid: Non-atomic operations (race conditions) const user = await collection('users').findOne({ userId: 'user123' }); await collection('users').updateOne( { userId: 'user123' }, { $set: { count: user.count + 1 } } );
-
Check return value
const result = await collection('users').incrementOne( { userId: 'user123' }, 'points', 50 ); if (result.matchedCount === 0) { throw new Error('User does not exist'); }
- Avoid using in loops
//❌ Avoid: N operations for (const userId of userIds) { await collection('users').incrementOne({ userId }, 'count'); } //✅ Recommendation: use updateMany await collection('users').updateMany( { userId: { $in: userIds } }, { $inc: { count: 1 } } );
| dimensions | incrementOne | updateOne({ $inc }) |
|---|---|---|
| Lines of code | 1-2 lines | 2-3 lines |
| Readability | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| Function | Equivalent | Equivalent |
A: incrementOne is a convenience method of updateOne({ $inc }), with clearer semantics and simpler code.
A: ✅ Yes! incrementOne is an atomic operation and is concurrency safe.
A: ✅ Yes! Just use negative numbers:
await collection('users').incrementOne({ userId: 'user123' }, 'credits', -10);A: MongoDB will automatically create fields, starting from 0 and increasing.
A: Use object form:
await collection('users').incrementOne(
{ userId: 'user123' },
{ count: 1, points: 10 }
);- updateOne() - Update a single document
- findOneAndUpdate() - Find and update
- upsertOne() - Update if it exists, insert if it does not exist
- MongoDB official documentation: $inc operator