$set 및 $unset을 사용한 updateOne과 updateMany
문서 전체를 대체하지 않고 하나 또는 여러 문서의 특정 필드를 수정합니다.
$set 및 $unset을 사용한 updateOne과 updateMany은(는) CoddyKit의 무료 MongoDB Academy 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 MongoDB Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. MongoDB Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.
The Two Main Update Methods
MongoDB provides two primary methods for modifying existing documents:
- updateOne(filter, update, options) — modifies the first document matching the filter. If multiple documents match, only one is updated.
- updateMany(filter, update, options) — modifies all documents matching the filter.
Both methods return a result object with matchedCount (how many documents matched the filter) and modifiedCount (how many were actually changed—some matching documents may already have the target value). Always verify modifiedCount in your application logic.
// updateOne: modify a specific document
const result = await db.collection('users').updateOne(
{ email: 'alice@example.com' }, // filter
{ $set: { lastLoginAt: new Date() } } // update
);
console.log(result.matchedCount); // 1
console.log(result.modifiedCount); // 1
// updateMany: modify all matching documents
const bulkResult = await db.collection('users').updateMany(
{ emailVerified: false },
{ $set: { needsVerification: true } }
);$set: Modifying Specific Fields
The $set operator sets the value of one or more fields. If a field does not exist, $set creates it. If it already exists, $set replaces its value. Only the specified fields are changed—all other fields in the document remain untouched.
This is the most important update operator and the one you will use in the vast majority of update operations. Never pass a plain document as the update argument without an operator—doing so replaces the entire document, losing all other fields.
// $set updates only the specified fields
db.users.updateOne(
{ _id: userId },
{ $set: { name: 'Alice Smith', updatedAt: new Date() } }
);
// Only 'name' and 'updatedAt' change; all other fields are preserved
// $set creates the field if it doesn't exist:
db.users.updateOne(
{ _id: userId },
{ $set: { newsletterOptIn: true } } // Added to doc even if it wasn't there
);
// $set on a nested field:
db.users.updateOne(
{ _id: userId },
{ $set: { 'address.city': 'New York' } } // Dot notation for nestedThe Whole-Document Replacement Trap
A critical MongoDB beginner mistake: if you pass a plain document as the update argument—without any update operators—MongoDB treats it as a full document replacement. The matched document is replaced entirely with the new document (preserving only _id). All other fields are lost.
This behavior is actually intentional and useful for replacing an entire document, but it is a common source of accidental data loss. Always use update operators ($set, $inc, etc.) unless you explicitly intend to replace the full document.
// DANGER: This REPLACES the entire document!
db.users.updateOne(
{ _id: userId },
{ name: 'Alice Smith' } // No $set operator!
);
// Before: { _id: ..., name: 'Alice', email: 'alice@...', age: 28 }
// After: { _id: ..., name: 'Alice Smith' } <-- email and age are GONE!
// CORRECT: Use $set to modify only name
db.users.updateOne(
{ _id: userId },
{ $set: { name: 'Alice Smith' } } // Only name changes
);$unset: Removing Fields
The $unset operator removes one or more fields from a document. The value you assign in $unset is ignored—conventionally set to '' or 1. The field is completely removed from the document, not set to null.
Use $unset when you want to clean up legacy fields during a schema migration, remove sensitive data (like a password reset token after it is used), or strip fields that should no longer be stored on certain documents.
// Remove specific fields from a document
db.users.updateOne(
{ _id: userId },
{ $unset: { passwordResetToken: '', passwordResetExpiry: '' } }
);
// Both fields are completely removed from the document
// $unset during schema migration: remove legacy field from all docs
db.users.updateMany(
{ legacyField: { $exists: true } },
{ $unset: { legacyField: '' } }
);
// Removes 'legacyField' from every document that has itCombining $set and $unset
You can combine multiple update operators in a single updateOne or updateMany call. They are applied atomically in a single operation—there is no window where the document is in a partially updated state.
This is important for schema migrations where you simultaneously add a new field and remove an old one. Doing it in one atomic operation prevents any client from reading a document in the transitional state where both old and new fields exist.
// Atomic schema migration: rename 'displayName' to 'username'
// (set new field, copy value from old field, remove old field)
db.users.updateMany(
{ displayName: { $exists: true } },
{
$rename: { displayName: 'username' } // Atomic rename
// $rename is equivalent to $set + $unset in one operator
}
);
// Or manually with $set + $unset + $currentDate:
db.orders.updateOne(
{ _id: orderId },
{
$set: { status: 'shipped', trackingNumber: 'UPS123' },
$unset: { processingNote: '' },
$currentDate: { shippedAt: true }
}
);$rename: Renaming Fields
The $rename operator atomically renames a field within a document. It is equivalent to $seting the new name with the old value and then $unseting the old name—but done in a single atomic step.
Use $rename when refactoring your schema and changing field names. It works correctly even when the destination field does not exist. If the source field does not exist, $rename does nothing (no error). It cannot rename fields across embedded documents.
// Rename 'fname' and 'lname' to 'firstName' and 'lastName'
db.users.updateMany(
{}, // All documents
{ $rename: { fname: 'firstName', lname: 'lastName' } }
);
// Before: { _id: ..., fname: 'Alice', lname: 'Smith' }
// After: { _id: ..., firstName: 'Alice', lastName: 'Smith' }
// If source field doesn't exist, $rename silently skips
// No error thrown$currentDate: Setting Timestamps
The $currentDate operator sets a field to the current date/time at the moment the update is executed on the server. Using server-side timestamps is more reliable than passing a date from the application, because it avoids clock skew between multiple application servers.
Set the value to true to use the BSON Date type, or { $type: 'timestamp' } for the BSON Timestamp type (used internally by the replication system). In application code, BSON Date is almost always what you want.
// Set multiple timestamp fields atomically
db.orders.updateOne(
{ _id: orderId, status: 'pending' },
{
$set: { status: 'processing' },
$currentDate: {
processingStartedAt: true, // BSON Date
lastModified: true
}
}
);
// processingStartedAt = server-side current time
// More reliable than Date.now() from applicationThe upsert Option
Setting { upsert: true } in the options tells MongoDB: if no document matches the filter, insert a new document that combines the filter fields and the update. This is the upsert (update-or-insert) pattern—useful for 'insert if not exists, update if exists' semantics without a separate read operation.
The inserted document contains the fields from both the filter and the $set. Check result.upsertedId to see if an insert occurred. Upserts are atomic—no race condition between checking existence and inserting.
// Upsert: update if exists, insert if not
const result = await db.collection('userPreferences').updateOne(
{ userId: userId }, // filter
{
$set: { theme: 'dark', language: 'en' }, // update
$setOnInsert: { createdAt: new Date() } // only on insert
},
{ upsert: true } // option
);
if (result.upsertedId) {
console.log('New preferences created:', result.upsertedId);
} else {
console.log('Existing preferences updated');
}updateMany: Bulk Field Changes
updateMany applies the same update to all matching documents in one operation. This is how you perform bulk schema migrations, add default values to missing fields, or update a batch of records based on a condition.
Be careful with updateMany({}, ...) (empty filter)—it modifies every document in the collection. Always include a filter that limits the scope. Consider adding a condition like { newField: { $exists: false } } to only process documents that need the change.
// Add default value to all existing docs missing the field
await db.collection('products').updateMany(
{ featured: { $exists: false } }, // Only docs without the field
{ $set: { featured: false } } // Set default
);
// Batch status update
await db.collection('orders').updateMany(
{ status: 'processing', createdAt: { $lt: new Date(Date.now() - 86400000 * 7) } },
{ $set: { status: 'stalled', stalledAt: new Date() } }
);
// Flag orders processing for more than 7 daysfindOneAndUpdate: Atomic Read-Modify
findOneAndUpdate(filter, update, options) atomically finds a document, updates it, and returns it in a single operation. This eliminates the race condition that exists when you do a separate findOne followed by an updateOne.
By default it returns the document before the update. Set { returnDocument: 'after' } to get the updated version. Combine with upsert: true to find-or-create patterns. This is ideal for claiming queue items, implementing counters, and any pattern where you need to both modify and read the document atomically.
// Claim the next pending job atomically
const job = await db.collection('jobs').findOneAndUpdate(
{ status: 'pending' }, // filter
{
$set: { status: 'claimed', workerId: workerId, claimedAt: new Date() }
},
{
sort: { priority: -1, createdAt: 1 }, // Pick highest priority, oldest
returnDocument: 'after' // Return updated document
}
);
if (job) {
await processJob(job); // job is fully updated in DB already
}Update Operators Reference Summary
MongoDB provides many update operators beyond and . Here is a quick reference of the most important ones you will encounter:
- : Set field value (create if absent)
- : Remove a field completely
- : Rename a field atomically
- : Increment/decrement a numeric field
- : Multiply a numeric field
- /: Conditionally update to smaller/larger value
- /: Add/remove array elements
- : Add to array only if unique
- : Set to server-side current date/time
// Multiple operators in one atomic update
db.userStats.updateOne(
{ userId: userId },
{
: { lastSeen: new Date(), status: 'active' },
: { pageViews: 1, sessionCount: 1 },
: { longestSession: sessionDuration },
: { visitedPages: currentPage },
: { updatedAt: true }
},
{ upsert: true }
);
// All six operators apply atomically in one round tripQuick Check
Test your understanding of MongoDB & NoSQL Databases concepts from this lesson.
Lesson Recap
In this lesson you learned: $set modifies specific fields without touching others—always use it rather than passing a bare document to avoid accidental full-document replacement, $unset removes fields entirely and is essential for schema migrations and cleaning up sensitive temporary data like password reset tokens, and upsert: true combined with $setOnInsert enables atomic find-or-create patterns without race conditions. Next up we explore numeric mutation operators: $inc, $mul, $min, and $max.
자주 묻는 질문
“$set 및 $unset을 사용한 updateOne과 updateMany” 강의는 무료인가요?
네 — “$set 및 $unset을 사용한 updateOne과 updateMany” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 MongoDB Academy 강의 전체를 잠금 해제할 수 있습니다. MongoDB Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“$set 및 $unset을 사용한 updateOne과 updateMany”에서 뭘 배우나요?
문서 전체를 대체하지 않고 하나 또는 여러 문서의 특정 필드를 수정합니다. 브라우저에서 직접 실행하는 실습 코드로 MongoDB Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
MongoDB Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 MongoDB Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.
“$set 및 $unset을 사용한 updateOne과 updateMany” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 MongoDB Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 MongoDB Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- $set 및 $unset을 사용한 updateOne과 updateMany
- 증가, 곱셈, 최솟값/최댓값 연산자
- 배열 업데이트 연산자: $push, $pull, $addToSet
- deleteOne과 deleteMany로 안전하게 문서 삭제하기