Operator Penambahan, Perkalian, serta Min/Maks
Lakukan perubahan numerik secara atomik menggunakan operator pembaruan $inc, $mul, $min, dan $max.
Operator Penambahan, Perkalian, serta Min/Maks adalah pelajaran MongoDB Academy gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar MongoDB Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus MongoDB Academy mencakup 4 pelajaran total.
Bagian dari pelajaran ini belum diterjemahkan dan ditampilkan dalam bahasa Inggris.
Atomic Numeric Updates
A common application pattern is reading a numeric value, computing a new value, and writing it back. If done as separate read and write operations, a race condition can occur: two concurrent requests might both read the same value, compute different results, and overwrite each other.
MongoDB's numeric update operators—$inc, $mul, $min, and $max—perform numeric mutations atomically at the database level. The computation and write happen in a single operation, eliminating race conditions without needing application-level locking.
$inc: Increment and Decrement
The $inc operator increments a numeric field by a given amount. Pass a negative value to decrement. If the field does not exist, $inc creates it with the given increment value as the initial value (treating a missing field as 0).
Common uses: view counters, like counts, inventory decrement, score tracking, retry attempt counters. Because the increment is atomic, multiple concurrent requests can all safely call $inc on the same document without losing any increments—every request's change is applied.
// Increment page view counter
db.posts.updateOne(
{ slug: 'mongodb-intro' },
{ $inc: { views: 1 } }
);
// views: 100 -> 101 (atomic, safe under concurrent traffic)
// Decrement stock (atomic inventory deduction)
db.products.updateOne(
{ _id: productId, stock: { $gte: 1 } }, // Only if in stock
{ $inc: { stock: -1 } }
);
// Increment two fields at once
db.users.updateOne(
{ _id: userId },
{ $inc: { loginCount: 1, totalSessions: 1 } }
);Atomic Inventory Decrement Pattern
The atomic inventory decrement is a classic MongoDB pattern. The filter includes both the document identifier AND the minimum stock condition: { _id: productId, stock: { $gte: quantity } }. If the stock check fails (not enough inventory), the filter matches zero documents, modifiedCount is 0, and no inventory is decremented.
This pattern guarantees that you never decrement stock below zero, even under high concurrent load with many simultaneous purchase attempts. No application-level locks or transactions are needed for this single-document atomic check-and-decrement.
async function decrementStock(productId, quantity) {
const result = await db.collection('products').updateOne(
{
_id: new ObjectId(productId),
stock: { $gte: quantity } // Only if enough stock
},
{
$inc: { stock: -quantity }
}
);
if (result.modifiedCount === 0) {
throw new Error('INSUFFICIENT_STOCK');
}
return true; // Successfully decremented
}$mul: Multiply a Field
The $mul operator multiplies a numeric field by a given factor. Like $inc, it is atomic. If the field does not exist, $mul creates it with a value of 0 (not the multiplier—multiplying 0 by any factor is still 0, which is the mathematically correct behavior for a missing/zero field).
Practical uses: applying bulk price changes (multiply all prices by 1.05 for a 5% price increase), scaling scores or weights, adjusting currency values. $mul is much more efficient than fetching each document, multiplying in code, and writing back.
// Apply 5% price increase to all electronics products
db.products.updateMany(
{ category: 'Electronics' },
{ $mul: { price: 1.05 } }
);
// price: 100.00 -> 105.00 (atomically for each document)
// Apply 10% discount to sale items
db.products.updateMany(
{ onSale: true },
{ $mul: { price: 0.90 } }
);
// Multiply two fields at once
db.metrics.updateOne(
{ _id: metricId },
{ $mul: { valueA: 2, valueB: 0.5 } }
);$min: Conditional Set to Smaller Value
The $min operator updates a field only if the new value is less than the current value. If the current value is already smaller, the field is left unchanged. If the field does not exist, $min sets it to the provided value.
This is useful for tracking record lows, ensuring a value never exceeds a ceiling, or recording the earliest date. For example, tracking the minimum price a product has ever been sold for, or the earliest sign-in date for a user.
// Track the all-time lowest price seen for a product
db.products.updateOne(
{ _id: productId },
{ $min: { lowestPriceEver: currentSalePrice } }
);
// Only updates if currentSalePrice < lowestPriceEver
// If lowestPriceEver is 45 and currentSalePrice is 50: no change
// If lowestPriceEver is 45 and currentSalePrice is 39: updates to 39
// Record earliest login date
db.users.updateOne(
{ _id: userId },
{ $min: { firstLoginAt: new Date() } }
);$max: Conditional Set to Larger Value
The $max operator is the complement of $min: it updates a field only if the new value is greater than the current value. This is ideal for tracking high scores, peak values, and latest dates.
Common applications: leaderboard high scores (only update if the new score beats the current best), tracking the maximum concurrent users, or recording the most recent activity timestamp (ensuring you never overwrite a later event with an earlier one).
// Leaderboard: only update score if new score is higher
db.leaderboard.updateOne(
{ userId: userId },
{
$max: { highScore: newScore },
$set: { lastPlayedAt: new Date() }
}
);
// highScore: 9500. newScore: 8700 -> no change (8700 < 9500)
// highScore: 9500. newScore: 9800 -> updates to 9800
// Track most recent activity timestamp
db.users.updateOne(
{ _id: userId },
{ $max: { lastActiveAt: new Date() } }
);Combining Numeric Operators
You can combine multiple numeric update operators in a single update operation. They are all applied atomically together. For example, incrementing a counter while also ensuring a timestamp is updated to the latest value.
Combining $inc with $max/$min is a powerful pattern for metrics tracking: increment total event count while conditionally updating peak values, all in a single round-trip to the database.
// Update user metrics: increment logins, track latest/earliest dates
db.userMetrics.updateOne(
{ userId: userId },
{
$inc: { totalLogins: 1 },
$max: { lastLoginAt: new Date() },
$min: { firstLoginAt: new Date() }
},
{ upsert: true } // Create document if user has no metrics yet
);
// All three numeric operators apply atomically in one operationUsing $inc for Distributed Counters
A common architecture challenge is maintaining accurate counters (page views, likes, downloads) at high throughput. Using $inc atomically on a document is highly reliable but can become a write bottleneck if millions of requests hit the same document per second—because MongoDB uses document-level locking for writes.
Patterns to scale high-throughput counters: counter sharding (split the counter across N documents and sum them), buffered batching (accumulate increments in memory and flush periodically), or time-bucketed counters (one document per time period to distribute writes).
// Time-bucketed counter: one document per hour
const hourBucket = new Date();
hourBucket.setMinutes(0, 0, 0); // Round to current hour
db.pageViews.updateOne(
{ page: 'home', hour: hourBucket },
{ $inc: { count: 1 } },
{ upsert: true } // Create bucket if first view this hour
);
// Writes distribute across hourly documents,
// reducing contention vs a single global counterNumeric Operators in the Aggregation Pipeline
The arithmetic concepts behind $inc, $mul, $min, and $max also appear in the aggregation pipeline as expression operators and accumulator operators. In $project you can compute new numeric fields with $add, $multiply, $subtract. In $group you use $sum, $avg, $min, $max as accumulators.
Understanding the update operator semantics now makes the aggregation operators intuitive—they perform the same mathematical operations, just in a pipeline context rather than a write context.
// Aggregation: compute total revenue and max single order
db.orders.aggregate([
{ $match: { status: 'completed' } },
{
$group: {
_id: '$customerId',
totalSpent: { $sum: '$total' }, // Sum of all totals
orderCount: { $sum: 1 }, // Count documents
maxOrder: { $max: '$total' }, // Largest single order
minOrder: { $min: '$total' } // Smallest single order
}
}
]);Decimal Precision With $inc
When incrementing floating-point values with $inc, be aware of floating-point precision issues inherited from IEEE 754 double arithmetic. For financial amounts, always use NumberDecimal (BSON Decimal128) to avoid rounding errors.
Incrementing a Decimal128 field with $inc requires passing a NumberDecimal value in the shell or Decimal128.fromString in Node.js. The result will be exact decimal arithmetic without the floating-point drift that plagues 64-bit double arithmetic.
// Floating-point issue with double
// 0.1 + 0.2 = 0.30000000000000004 in IEEE 754!
db.accounts.updateOne(
{ _id: accountId },
{ $inc: { balance: 0.1 } } // Potential precision drift
);
// Correct: use Decimal128 for financial amounts
const { Decimal128 } = require('mongodb');
db.accounts.updateOne(
{ _id: accountId },
{ $inc: { balance: Decimal128.fromString('0.10') } }
);
// Exact decimal arithmetic - no floating point errorsAtomic Check-and-Update Patterns
A powerful MongoDB pattern is the conditional update with filter: include the condition you want to check as part of the query filter rather than reading first and deciding in application code. This makes the check-and-update atomic, eliminating race conditions.
Patterns: decrement stock only if sufficient quantity (filter includes stock: { : qty }), update only if a field has a specific value (optimistic locking pattern), or apply a promotion only if the user has not already received it. The operation either succeeds (modifiedCount: 1) or the condition was not met (modifiedCount: 0).
// Optimistic locking: update only if version matches
async function updateWithLock(id, currentVersion, newData) {
const result = await db.collection('items').updateOne(
{ _id: id, version: currentVersion }, // Version check in filter!
{
: { ...newData },
: { version: 1 } // Increment version on each update
}
);
if (result.modifiedCount === 0) {
throw new Error('VERSION_CONFLICT');
// Another process updated this document since we read it
}
}Quick Check
Test your understanding of MongoDB & NoSQL Databases concepts from this lesson.
Lesson Recap
In this lesson you learned: $inc atomically increments or decrements a numeric field—ideal for counters, view counts, and inventory decrements combined with a stock-check filter to prevent over-selling, $mul multiplies a field by a factor for bulk price adjustments and scaling operations, and $min/$max conditionally update only when the new value is smaller/larger than the current—perfect for tracking all-time records, high scores, and earliest/latest timestamps. Next up we explore array update operators: $push, $pull, and $addToSet.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Operator Penambahan, Perkalian, serta Min/Maks” gratis?
Ya — teks lengkap “Operator Penambahan, Perkalian, serta Min/Maks” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus MongoDB Academy, upgrade ke CoddyKit PRO. Kursus MongoDB Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Operator Penambahan, Perkalian, serta Min/Maks”?
Lakukan perubahan numerik secara atomik menggunakan operator pembaruan $inc, $mul, $min, dan $max. Kamu berlatih MongoDB Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai MongoDB Academy?
Tidak diperlukan pengalaman sebelumnya. MongoDB Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.
Berapa lama pelajaran “Operator Penambahan, Perkalian, serta Min/Maks” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran MongoDB Academy ini?
Ya. Setiap pelajaran MongoDB Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- updateOne dan updateMany dengan $set dan $unset
- Operator Penambahan, Perkalian, serta Min/Maks
- Operator Pembaruan Array: $push, $pull, $addToSet
- Menghapus Dokumen dengan Aman menggunakan deleteOne dan deleteMany