Dataset used:
sample_mflix(collectionmovies)
Table of Contents
- 1.1 Understanding When Analysts Modify Data
- 1.2 Distinguishing Between Read and Write Operations
- 1.3 Avoiding Unintentional Data Loss During Updates
- 1.4 Deciding When to Escalate to a Data Engineer
- 1.5 Demo: Setting Up Your Environment for Safe Modifications
- 2.1 Demo: Using updateOne() to Modify a Single Document
- 2.2 Demo: Using updateMany() to Modify Multiple Documents
- 2.3 Demo: Applying Common Update Operators in Practice
- 2.4 Demo: Updating Nested Fields in Structured Documents
- 2.5 Demo: Confirming the Results of an Update Operation
- 3.1 Deciding When to Replace Instead of Update
- 3.2 Demo: Replacing a Document Using replaceOne()
- 3.3 Demo: Removing Documents Using deleteOne() and deleteMany()
- 3.4 Understanding the Permanence of Deletions
- 4.1 Demo: Previewing and Validating Updates with find()
- 4.2 Demo: Simulating Updates with Dummy Fields
- 4.3 Demo: Tracking Changes with Timestamps and Metadata
- 4.4 Communicating Before Modifying Shared Datasets
1.
2. Deciding When and How to Modify Data in MongoDB
1.1 Understanding When Analysts Modify Data
Every analyst encounters this moment: we spot a typo, a strange date, or a missing value and ask ourselves “should I fix this, can I do this, or will I make things worse?” » This course confidently answers these questions: not just how to change data in MongoDB, but when it makes sense, why it matters, and what to check before and after each change.
The fundamental truth: Any data change is a decision. If it’s a decision, it needs to be informed — which means reviewing the filters, testing the logic, and validating the impact after the update.
The four typical change scenarios for analysts
| Scenario | Description | Example |
|---|---|---|
| Inconsistent values | Standardize mixed values for the same field | The rating field contains “PG-13”, “pg-13”, “Pg13” → normalize everything to “PG-13” |
| Missing values | Fill in or report a missing field | runtime is null → fill with a reliable value and add runtimeWasMissing: true |
| Inconsistent formatting | Standardize date or identifier structures | Dates in numeric vs alphabetical format → convert everything to ISO 8601 |
| Enrichment | Add fields for analysis or export | Add avgScore (average of criticsScore and audienceScore) + dateExported |
Illustration of the four scenarios
Scenario 1 — Cleaning up inconsistent values:
The rated field contains every imaginable variation of “PG-13”. If we try to group or filter on this field, it is impossible. We standardize everything to “PG-13”: clean, reliable, and easy to filter.
Scenario 2 — Fill in or report missing values:
A movie document where runtime is null. Leaving it as is can break the average calculations. We fill with a confidence value and add a runtimeWasMissing: true flag. No guessing — just clarity.
Scenario 3 — Format normalization: One date may be all numbers, another may use letters. We cannot sort or compare reliably. We convert everything to a single ISO format — which gives consistency that MongoDB can use.
Scenario 4 — Enrichment for export or visualization:
The document already has criticsScore and audienceScore. We go further by adding avgScore and dateExported. These additions make the data easier to use in downstream reports, dashboards or workflows.
Key message: Modifying data is not just a matter of write access. It’s about intention, clarity, and building the habit of checking every update before and after it happens.
1.2 Distinguishing Between Read and Write Operations
Before you even think about changing data, you need to understand one fundamental thing: read and write operations look similar on the surface, but what they do under the hood is completely different.
Analogy
- Reading data is like window shopping. You can browse, watch, take notes, filter — but nothing changes.
- Writing data is like entering the store with a marker and changing price tags. We directly affect the content of the database.
Comparison table: Read vs. write operations
| Criterion | Read operations | Write operations |
|---|---|---|
| Impact on data | None | Direct — modifies content |
| Reversibility | Nothing to cancel | Often non-reversible (without backup) |
| Re-execution security | Always safe | Sometimes safe, not always |
| Risk level | Low | High |
Read operations
| Order | Description |
|---|---|
find() | Returns all matching documents |
findOne() | Stops at first matching document |
aggregate() | Filter, reshape and group documents |
These commands are always safe. They can be run again and again without risking modifying the data.
Write operations
| Order | Description |
|---|---|
insertOne() | Add a new document |
updateMany() | Edit documents that match the filter |
deleteOne() | Deletes a document completely |
These commands are powerful, but with that power must come some caution.
Final Principle: Playback commands allow exploration. Writing commissions are a commitment. They change the state of the data.
1.3 Avoiding Unintentional Data Loss During Updates
Most of the time, when data gets corrupted, it’s not because someone wanted to corrupt it — it’s because someone made a small assumption that turned into a big problem.
Five common errors when updating
Error #1 — Running an update without filter
If we forget the filter, MongoDB applies the update to all documents in the collection. This is almost never what we want.
Correction: Always include a filter. Be specific about which documents need to change.
Error #2 — Accidentally deleting fields
What happens: we omit a field in the update thinking that it will remain as is. But MongoDB doesn’t think like that — it assumes you want the field to disappear. To keep the structure while emptying the value, you must explicitly set the field to null.
Fix: Use
$set: { field: null }to keep the field with an intentional empty value.
Error #3 — Typos in field names
If you make a mistake in a field name, MongoDB does not stop. It simply creates a new field with that misspelled name. This produces confusing results and inconsistent data.
Fixed: Use
find()first to preview field names that already exist. Easier to fix a fault before the update runs.
Error #4 — Running a Blind Update
Running an update without checking which documents it will affect is like crossing a busy street without looking. We could be okay, but maybe not.
Correction: Always test your filter with
find()first. Ensure that it returns exactly the expected documents.
Mistake #5 — Assuming data is clean and consistent
Do not fall into the trap of thinking that each document uses the same types of fields or formats. MongoDB will not complain if you apply a string to a field that usually stores numbers.
Correction: Check the data type and format before making changes. A quick check now can prevent weird bugs later.
Important reminder: There is no confirmation pop-up, no “are you sure?” prompt, no friendly warning before potentially erasing data. MongoDB assumes you know what you’re doing, even if you don’t. So that’s our responsibility — filter, preview, validate.
1.4 Deciding When to Escalate to a Data Engineer
Not all changes are equal, and knowing which changes belong to the analyst or engineer helps decide whether to proceed or escalate.
Analyst area
The analyst’s work generally includes technical corrections:
- Cleaning up invalid values
- Fix typos
- Filling missing fields
- Changes of limited scope (updating a controlled number of records)
- Working on specific documents matching a known condition
- Safe changes that will not break application logic
Data engineer area
Engineers manage structural changes:
- Adding new fields
- Renaming existing fields
- Document structure transformation
- Updates with global system impact (affecting multiple downstream services or pipelines)
- Changes to entire collections
- Schema enforcement
It’s not about job title — it’s about safety and accountability.
Escalation Decision Checklist
| Question | If YES → |
|---|---|
| Does the update affect multiple collections? | Involve Engineering |
| Could the change accidentally break the application logic? | Request a technical review |
| Does the change affect downstream pipelines or services? | Alert the team concerned |
| Does the update affect tens of thousands of documents? | Consult before proceeding |
| Are there any schema constraints to respect? | Check with Engineering |
Principle: If the change crosses the threshold from tactical to structural, it’s time to stop and reevaluate.
1.5 Demo: Setting Up Your Environment for Safe Modifications
Prerequisites
- A MongoDB Atlas cluster (with sample data loaded)
- MongoDB Compass (visual interface)
- MongoDB Shell (command line interface)
Configuring MongoDB Atlas
- In the Atlas interface, confirm that the example dataset is loaded (green banner)
- In the left sidebar, under DATABASE, click Data Explorer
- Three databases are visible:
admin,local,sample_mflix - The main playground is
sample_mflix - Collections available:
movies,comments,users
Explore the movies collection in Compass
movies documents contain fields like title, year, cast, ratings, as well as deep nested structures. Fields can be expanded or contracted to explore details.
Note: Compass and Atlas Data Explorer allow you to edit values directly, but in this course all work is done through the Shell with controlled updates.
Connection via Shell
- From the Atlas cluster screen, click Connect
- Choose Shell
- Copy the generated connection string
- In the terminal, paste and execute the command
- Enter password when prompted
- Connection successful message appears with MongoDB version
Environment Check Commands
// Sélectionner la base de données de travail
use sample_mflix
// Lister les collections disponibles
show collections
// Examiner un document de la collection movies
db.movies.findOne()
// Vérifier la base de données active
db
3.
4. Performing Targeted Updates Using Structured Commands
2.1 Demo: Using updateOne() to Modify a Single Document
updateOne() is the tool to make surgical modifications on a single document. This is the most precise command when you want to change exactly one record without affecting the others.
Syntax
db.collection.updateOne(
{ /* filtre */ }, // Quel document cibler
{ /* opération */ } // Quoi modifier
)
Result object
After each updateOne(), MongoDB returns a result object with the following properties:
| Property | Description |
|---|---|
acknowledged | true if the command was processed successfully |
matchedCount | Number of documents matching the filter |
modifiedCount | Number of documents actually modified |
upsertedCount | Number of documents inserted (0 if no upsert) |
upsertedId | null if no upsert |
Reminder: An
upsertis a fallback mechanism that inserts a new document if nothing matches the filter.
Example 1 — Change the rating of a well-known film
Change the rating of “The Princess Diaries” from “G” to “PG-13”.
// Prévisualiser avant modification
db.movies.find(
{ title: "The Princess Diaries" },
{ title: 1, rated: 1, _id: 0 }
).limit(1)
// Exécuter la mise à jour
db.movies.updateOne(
{ title: "The Princess Diaries" },
{ $set: { rated: "PG-13" } }
)
// Confirmer après modification
db.movies.find(
{ title: "The Princess Diaries" },
{ title: 1, rated: 1, _id: 0 }
).limit(1)
Example 2 — Update multiple fields in a single command
Correct the release year and rating of “The Net”.
// Prévisualiser
db.movies.find(
{ title: "The Net" },
{ title: 1, year: 1, rated: 1, _id: 0 }
).limit(1)
// Mise à jour de plusieurs champs simultanément
db.movies.updateOne(
{ title: "The Net" },
{ $set: { year: 1996, rated: "PG-13" } }
)
// Confirmer
db.movies.find(
{ title: "The Net" },
{ title: 1, year: 1, rated: 1, _id: 0 }
).limit(1)
Example 3 — More precise filter with multiple conditions
Update “The Negotiator” only for the version released in 1998.
db.movies.find(
{ title: "The Negotiator", year: 1998 },
{ title: 1, year: 1, rated: 1, _id: 0 }
).limit(1)
db.movies.updateOne(
{ title: "The Negotiator", year: 1998 },
{ $set: { rated: "PG-13" } }
)
db.movies.find(
{ title: "The Negotiator", year: 1998 },
{ title: 1, year: 1, rated: 1, _id: 0 }
).limit(1)
When the dataset contains similar or duplicate entries, filters like this aren’t just useful — they’re absolutely necessary.
Example 4 — Targeting via _id for maximum precision
Mark movies with a runtime > 220 minutes as isOutlier: true. Using the unique _id ensures that we update exactly the previewed record.
// Trouver le film concerné
db.movies.find(
{ runtime: { $gt: 220 } },
{ title: 1, runtime: 1 }
).limit(1)
// Mettre à jour via _id (remplacer par l'_id réel retourné ci-dessus)
db.movies.updateOne(
{ _id: ObjectId("PASTE_OBJECT_ID_HERE") },
{ $set: { isOutlier: true } }
)
// Confirmer
db.movies.find(
{ _id: ObjectId("PASTE_OBJECT_ID_HERE") },
{ title: 1, isOutlier: 1 }
)
Example 5 — Update an array
Simplify the language list of “The Terminal”.
db.movies.find(
{ title: "The Terminal" },
{ title: 1, languages: 1, _id: 0 }
).limit(1)
db.movies.updateOne(
{ title: "The Terminal" },
{ $set: { languages: ["English", "French"] } }
)
db.movies.find(
{ title: "The Terminal" },
{ title: 1, languages: 1, _id: 0 }
).limit(1)
Takeaway: updateOne() is the ideal tool for precise, one-off modifications that avoid unintentional side effects. Always preview before updating and confirm after.
2.2 Demo: Using updateMany() to Modify Multiple Documents
updateMany() applies the same change to a group of documents matching a specific condition. Whether filling in missing values, tagging categories, or marking outliers, updateMany() does it efficiently.
Syntax
db.collection.updateMany(
{ /* filtre */ }, // Quels documents cibler
{ /* opération */ } // Quoi modifier
)
The syntax is identical to
updateOne(), the difference being that all the corresponding documents are modified.
Example 1 — Add a decade field to films from the 1980s
// Prévisualiser quelques documents
db.movies.find(
{ year: { $gte: 1980, $lt: 1990 } },
{ title: 1, year: 1, _id: 0 }
).limit(5)
// Exécuter la mise à jour en batch
db.movies.updateMany(
{ year: { $gte: 1980, $lt: 1990 } },
{ $set: { decade: "1980s" } }
)
// Confirmer les documents mis à jour
db.movies.find(
{ decade: "1980s" },
{ title: 1, year: 1, decade: 1, _id: 0 }
).limit(5)
Example 2 — Add a default rating to unentered films
Use $exists: false to target documents where the rated field is missing.
// Prévisualiser les documents sans le champ rated
db.movies.find(
{ rated: { $exists: false } },
{ title: 1, rated: 1, _id: 0 }
).limit(5)
// Mise à jour en batch
db.movies.updateMany(
{ rated: { $exists: false } },
{ $set: { rated: "Not Rated" } }
)
// Confirmer
db.movies.find(
{ rated: "Not Rated" },
{ title: 1, rated: 1, _id: 0 }
).limit(5)
The update result shows thousands of matching and modified documents — a quick and secure way to bring consistency to the data.
Example 3 — Abbreviation of a gender label
Replace “Documentary” with “Docu” in the genres table.
// Prévisualiser les documents affectés
db.movies.find(
{ genres: "Documentary" },
{ title: 1, genres: 1, _id: 0 }
).limit(5)
// Mise à jour en batch (écrase le tableau entier)
db.movies.updateMany(
{ genres: "Documentary" },
{ $set: { genres: ["Docu"] } }
)
// Confirmer
db.movies.find(
{ genres: "Docu" },
{ title: 1, genres: 1, _id: 0 }
).limit(5)
The update confirms the change on more than 1,800 documents.
Example 4 — Tag short films
Add isShort: true to movies with a runtime less than 60 minutes.
// Prévisualiser les films courts
db.movies.find(
{ runtime: { $lt: 60 } },
{ title: 1, runtime: 1, _id: 0 }
).limit(5)
// Appliquer la mise à jour en batch
db.movies.updateMany(
{ runtime: { $lt: 60 } },
{ $set: { isShort: true } }
)
// Confirmer
db.movies.find(
{ isShort: true },
{ title: 1, runtime: 1, isShort: 1, _id: 0 }
).limit(5)
Takeaway: updateMany() allows you to correct the structure, fill in gaps, standardize values or add entirely new fields to several documents in a single operation. The key: write a safe filter, preview, apply the change, and confirm.
2.3 Demo: Applying Common Update Operators in Practice
MongoDB update operators are special keywords that define exactly how a document should be modified.
The four main operators
| Operator | Role | Use cases |
|---|---|---|
$set | Add or modify a field | Correct a value, add a new field |
$unset | Delete a field | Remove an obsolete or unnecessary field |
$rename | Rename a field | Harmonize the diagram without manually copying |
$inc | Increment a numeric value | Counters, score adjustments or durations |
Demo — $set: Modify or create a field
// Prévisualiser
db.movies.find(
{ title: "Catch Me If You Can" },
{ title: 1, rated: 1, _id: 0 }
).limit(1)
// Appliquer la mise à jour
db.movies.updateOne(
{ title: "Catch Me If You Can" },
{ $set: { rated: "R" } }
)
// Confirmer
db.movies.find(
{ title: "Catch Me If You Can" },
{ title: 1, rated: 1, _id: 0 }
).limit(1)
Demo — $unset: Delete an existing field
// Prévisualiser avant suppression
db.movies.find(
{ title: "Catch Me If You Can" },
{ title: 1, plot: 1, _id: 0 }
).limit(1)
// Supprimer le champ (la valeur "" est ignorée — seule la clé compte)
db.movies.updateOne(
{ title: "Catch Me If You Can" },
{ $unset: { plot: "" } }
)
// Confirmer que le champ a disparu
db.movies.find(
{ title: "Catch Me If You Can" },
{ title: 1, plot: 1, _id: 0 }
).limit(1)
Demo — $rename: Rename a field
// Prévisualiser un film d'action avec le champ plot
db.movies.find(
{ genres: "Action", plot: { $exists: true } },
{ title: 1, plot: 1, _id: 0 }
).limit(1)
// Renommer plot → fullPlot (le contenu est préservé, seul le nom change)
db.movies.updateOne(
{ title: "PASTE_TITLE_HERE" },
{ $rename: { plot: "fullPlot" } }
)
// Confirmer le renommage
db.movies.find(
{ title: "PASTE_TITLE_HERE" },
{ title: 1, fullPlot: 1, _id: 0 }
).limit(1)
Demo — $inc: Increment a numeric value
// Prévisualiser le runtime actuel
db.movies.find(
{ title: "The Terminal" },
{ title: 1, runtime: 1, _id: 0 }
).limit(1)
// → runtime: 128
// Incrémenter de 5 minutes
db.movies.updateOne(
{ title: "The Terminal" },
{ $inc: { runtime: 5 } }
)
// Confirmer → runtime: 133
db.movies.find(
{ title: "The Terminal" },
{ title: 1, runtime: 1, _id: 0 }
).limit(1)
Demo — Combine $set and $inc in a single command
MongoDB allows using multiple operators in a single update.
// Ajouter un tag ET incrémenter le runtime en un seul appel
db.movies.updateOne(
{ title: "The Terminal" },
{
$set: { tagged: true },
$inc: { runtime: 10 }
}
)
// Confirmer les deux changements
db.movies.find(
{ title: "The Terminal" },
{ title: 1, runtime: 1, tagged: 1, _id: 0 }
).limit(1)
// → runtime: 143, tagged: true
Takeaway: Each of these operators is accurate, reliable, and incredibly useful in real-world scenarios. The intelligent combination of operators keeps documents well structured and up to date.
2.4 Demo: Updating Nested Fields in Structured Documents
MongoDB allows you to update fields at any nesting level using dot notation.
Principle of dot notation
"objet.sous-objet.champ"
"awards.wins"
"tomatoes.viewer.rating"
"tomatoes.critic.confidence"
Example 1 — Update a top-level nested field
Modify awards.wins for “The Godfather”.
// Prévisualiser la valeur actuelle
db.movies.find(
{ title: "The Godfather" },
{ title: 1, "awards.wins": 1, _id: 0 }
).limit(1)
// → awards.wins: 33
// Mettre à jour avec dot notation
db.movies.updateOne(
{ title: "The Godfather" },
{ $set: { "awards.wins": 55 } }
)
// Confirmer
db.movies.find(
{ title: "The Godfather" },
{ title: 1, "awards.wins": 1, _id: 0 }
).limit(1)
// → awards.wins: 55
Example 2 — Edit a deeply nested field
Modify tomatoes.viewer.rating (two levels of nesting).
// Prévisualiser
db.movies.find(
{ title: "The Godfather" },
{ title: 1, "tomatoes.viewer.rating": 1, _id: 0 }
).limit(1)
// → tomatoes.viewer.rating: 4.4
// Mettre à jour
db.movies.updateOne(
{ title: "The Godfather" },
{ $set: { "tomatoes.viewer.rating": 4.5 } }
)
// Confirmer → 4.5
db.movies.find(
{ title: "The Godfather" },
{ title: 1, "tomatoes.viewer.rating": 1, _id: 0 }
).limit(1)
Example 3 — Add a new nested field
Create tomatoes.critic.confidence which did not yet exist.
// Vérifier que le champ n'existe pas
db.movies.find(
{ title: "The Godfather" },
{ title: 1, "tomatoes.critic": 1, _id: 0 }
).limit(1)
// Ajouter le nouveau champ imbriqué
db.movies.updateOne(
{ title: "The Godfather" },
{ $set: { "tomatoes.critic.confidence": "High" } }
)
// Confirmer que le champ existe maintenant
db.movies.find(
{ title: "The Godfather" },
{ title: 1, "tomatoes.critic": 1, _id: 0 }
).limit(1)
Example 4 — Increment a nested numeric field
Increase tomatoes.viewer.numReviews by 1.
// Vérifier le compte actuel
db.movies.find(
{ title: "The Godfather" },
{ title: 1, "tomatoes.viewer.numReviews": 1, _id: 0 }
).limit(1)
// → tomatoes.viewer.numReviews: 73
// Incrémenter
db.movies.updateOne(
{ title: "The Godfather" },
{ $inc: { "tomatoes.viewer.numReviews": 1 } }
)
// Confirmer → 74
db.movies.find(
{ title: "The Godfather" },
{ title: 1, "tomatoes.viewer.numReviews": 1, _id: 0 }
).limit(1)
Takeaway: MongoDB’s dot notation allows fields to be updated at any nesting level. Whether to modify an existing value, add a new one or increment a digital counter, the approach remains consistent: preview the document, apply the change, check the result.
2.5 Demo: Confirming the Results of an Update Operation
MongoDB returns a result object after each write operation. For large-scale updates, this object is critical.
Store the result in a variable
let result1 = db.movies.updateOne(
{ title: "The Terminal" },
{ $set: { rated: "R" } }
)
// Explorer chaque propriété
result1.acknowledged // true
result1.matchedCount // 1
result1.modifiedCount // 1 si la valeur a changé
result1.upsertedCount // 0 (pas d'upsert)
result1.upsertedId // null
Complete example with validation
// Prévisualiser avant
db.movies.find(
{ title: "The Terminal" },
{ title: 1, rated: 1, _id: 0 }
).limit(1)
// → rated: "PG-13"
// Exécuter et capturer le résultat
let result1 = db.movies.updateOne(
{ title: "The Terminal" },
{ $set: { rated: "R" } }
)
// Inspecter l'objet résultat complet
({
acknowledged: result1.acknowledged, // true
matchedCount: result1.matchedCount, // 1
modifiedCount: result1.modifiedCount, // 1
upsertedCount: result1.upsertedCount, // 0
upsertedId: result1.upsertedId // null
})
// Confirmer après
db.movies.find(
{ title: "The Terminal" },
{ title: 1, rated: 1, _id: 0 }
).limit(1)
// → rated: "R"
Handling the case where the filter does not match anything
// Tentative de mise à jour sur un film inexistant
let result5 = db.movies.updateOne(
{ title: "The Movie That Doesn't Exist" },
{ $set: { rated: "PG" } }
)
// Afficher l'objet résultat
({
acknowledged: result5.acknowledged, // true
matchedCount: result5.matchedCount, // 0
modifiedCount: result5.modifiedCount, // 0
upsertedCount: result5.upsertedCount, // 0
upsertedId: result5.upsertedId // null
})
// Logique conditionnelle basée sur le résultat
if (result5.modifiedCount > 0) {
"✅ Mise à jour réussie."
} else if (result5.matchedCount === 0) {
"⚠️ Aucun document ne correspond au filtre — vérifier la requête."
} else {
"ℹ️ Document trouvé mais aucune mise à jour nécessaire — la valeur est peut-être déjà correcte."
}
Critical reminder: acknowledged: true does not mean that data has changed. It only means that MongoDB received and processed the command. Always check matchedCount and modifiedCount.
Final takeaway of module 2: A single line can modify thousands of documents. Make sure it’s the right one.
5.
6. Replacing and Removing Documents Safely
3.1 Deciding When to Replace Instead of Update
Sometimes in MongoDB, we just need to change one or two lines. Other times, we look at a document and think, “This has to go.” This is where replaceOne() comes in.
When to use updateOne()?
- To change only specific fields without disrupting the rest of the document
- For small targeted corrections (correct a typo, update a single value)
- To keep the majority of the document intact
- To preserve additional fields that are not part of the update but are important to other parts of the application
- To avoid loss of fields — only specified fields change, everything else is preserved
When to use replaceOne()?
- To change entire structure of the document because the current layout no longer works
- To completely rebuild the document when the current data is obsolete, inconsistent, or too messy to correct piece by piece
- To delete additional fields — any fields missing from the replacement document are deleted instantly
- To perform a clean reset — keep only the essential fields and clear everything else in a single controlled operation
The upsert option
When enabled, upsert: true allows replaceOne() to:
- Replace the document if it exists
- Insert new document if no match found
This way, we always get the desired document, whether a match was found or not.
Synthetic comparison
| Criterion | updateOne() | replaceOne() |
|---|---|---|
| Scope | Specific fields | Entire document |
| Fields not mentioned | Preserved | Deleted |
| Use cases | Small targeted corrections | Complete restructuring |
| Risk of loss | Low | High if poorly planned |
| Planning Required | Minimal | Important |
Key message: Replacement is a matter of intentional design. We decide exactly what stays and what disappears. It takes more planning than a simple $set, but the result is a clean, minimal document, exactly as intended.
3.2 Demo: Replacing a Document Using replaceOne()
Syntax
db.collection.replaceOne(
{ /* filtre */ }, // Quel document cibler
{ /* nouveau document */ } // Document de remplacement complet
)
MongoDB keeps the original _id and replaces everything else with the new document. If a field is missing from the replacement document, it will be permanently deleted.
Example 1 — Change the structure and delete unnecessary fields
Restructure “The Negotiator” (1998): create a nested release object and remove the awards and tomatoes fields.
// Avant
db.movies.find(
{ title: "The Negotiator", year: 1998 },
{ title: 1, year: 1, rated: 1, runtime: 1, awards: 1, tomatoes: 1, _id: 0 }
).limit(1)
// Remplacement : nouvelle structure + pas d'awards/tomatoes
db.movies.replaceOne(
{ title: "The Negotiator", year: 1998 },
{
title: "The Negotiator",
release: { year: 1998, country: "USA" },
rated: "PG-13",
runtime: 140
}
)
// Après : structure plus propre, awards et tomatoes ont disparu
db.movies.find(
{ title: "The Negotiator" },
{ title: 1, "release.year": 1, rated: 1, runtime: 1, awards: 1, tomatoes: 1, _id: 0 }
).limit(1)
Example 2 — Resetting to minimum identity fields
Keep only the title and year for “The Net”.
// Avant (plusieurs champs)
db.movies.find(
{ title: "The Net" },
{ title: 1, year: 1, rated: 1, runtime: 1, genres: 1, _id: 0 }
).limit(1)
// Remise à zéro : garder seulement l'essentiel
db.movies.replaceOne(
{ title: "The Net" },
{
title: "The Net",
year: 1996
}
)
// Après : seulement title et year restent
db.movies.find(
{ title: "The Net" },
{ title: 1, year: 1, rated: 1, runtime: 1, genres: 1, _id: 0 }
).limit(1)
Example 3 — Insert or replace with upsert: true
Check if “Pluralsight Demo Movie” exists, then insert or replace it.
// Avant (aucun résultat attendu)
db.movies.find(
{ title: "Pluralsight Demo Movie" },
{ title: 1, year: 1, rated: 1, runtime: 1, genres: 1, languages: 1, release: 1, _id: 0 }
).limit(1)
// Remplacement avec upsert: true
db.movies.replaceOne(
{ title: "Pluralsight Demo Movie" },
{
title: "Pluralsight Demo Movie",
year: 2025,
rated: "PG",
runtime: 105,
genres: ["Educational", "Tech"],
languages: ["English"],
release: { year: 2025, country: "USA" },
lastModified: new Date()
},
{ upsert: true }
)
// Après : le nouveau document est maintenant dans la collection
db.movies.find(
{ title: "Pluralsight Demo Movie" },
{ title: 1, year: 1, rated: 1, runtime: 1, genres: 1, languages: 1, release: 1, _id: 0 }
).limit(1)
Takeaway: The override provides full control over the document structure. We can restructure, clean or start from scratch. But if a field is not included in the replacement document, it is lost. Plan the structure carefully.
3.3 Demo: Removing Documents Using deleteOne() and deleteMany()
Deleting documents in MongoDB removes them from the collection entirely. Deletions are irreversible.
Syntax
// Supprimer un seul document (le premier correspondant au filtre)
db.collection.deleteOne({ /* filtre */ })
// Supprimer tous les documents correspondants
db.collection.deleteMany({ /* filtre */ })
Example 1 — Precise deletion with deleteOne()
// Avant : confirmer que le document existe
db.movies.find(
{ title: "Pluralsight Demo Movie" },
{ title: 1, year: 1, rated: 1, _id: 1 }
).limit(1)
// Supprimer
db.movies.deleteOne({ title: "Pluralsight Demo Movie" })
// Après : aucun résultat
db.movies.find(
{ title: "Pluralsight Demo Movie" },
{ title: 1, year: 1, _id: 0 }
).limit(1)
Example 2 — Delete all movies of a specific length
// Avant : voir les films concernés
db.movies.find(
{ runtime: 60 },
{ title: 1, year: 1, runtime: 1, _id: 0 }
).limit(5)
// Supprimer tous les films de 60 minutes
db.movies.deleteMany({ runtime: 60 })
// → 61 documents supprimés
// Après : aucun résultat
db.movies.find(
{ runtime: 60 },
{ title: 1, year: 1, runtime: 1, _id: 0 }
).limit(5)
Example 3 — Count then delete (recommended pattern)
Use variables to store counts before deletion — this ensures transparency and security.
// Compter les documents correspondants
const oldMoviesCount = db.movies.countDocuments({ year: { $lt: 1920 } })
print("Films à supprimer :", oldMoviesCount)
// → 18
// Supprimer
const res3 = db.movies.deleteMany({ year: { $lt: 1920 } })
print("Nombre supprimé :", res3.deletedCount)
// → 18
// Après : aucun film avant 1920
db.movies.find(
{ year: { $lt: 1920 } },
{ title: 1, year: 1, _id: 0 }
).limit(5)
Example 4 — Deletion via regular expression
// Compter les documents avec "gold" dans le titre (insensible à la casse)
const goldMoviesCount = db.movies.countDocuments({ title: /gold/i })
print("Films à supprimer :", goldMoviesCount)
// → 56
// Supprimer
const res4 = db.movies.deleteMany({ title: /gold/i })
print("Nombre supprimé :", res4.deletedCount)
// → 56
// Confirmer
db.movies.find(
{ title: /gold/i },
{ title: 1, year: 1, _id: 0 }
).limit(5)
Recommended pattern: In real MongoDB use cases, we often see this pattern:
- Store the count of matching documents in a variable before deleting
- Store the delete result in a variable to check
deletedCount - Compare the two numbers to confirm that everything went according to plan
Takeaway: deleteOne() and deleteMany() give fine-grained control over which documents are deleted — but this control is only as good as the filter used. Always preview with find(), and avoid unpleasant surprises while keeping collections light and relevant.
3.4 Understanding the Permanence of Deletions
In MongoDB, deleting a document is a one-way street with no U-turn.
Four truths about MongoDB deletes
1. No rollback One cannot simply undo a delete operation as one could do with a transaction in other systems. Once the deletion has been processed, the original state of the document has disappeared — unless we had a backup.
2. No trash Nothing is moved to a temporary storage area. You cannot look in a recycled folder later to hope to find the document and restore it. Once deleted, it is erased entirely from the collection.
3. References may break If other documents depended on what was just deleted, the references may break. Any linked ID or dependent record may now point to nothing — which can lead to missing data in the application or unexpected errors for end users.
4. No integrated audit log MongoDB does not store a record of deleted documents. There is no built-in log showing what was deleted or by whom — unless auditing or logging had been enabled before the operation.
Conclusion: Deleting is easy, too easy — but recovering is not. Without backups or snapshots, the only recovery option is time travel, and that doesn’t exist yet. This is why you have to check your filter, check it again, and maybe even a third time before pressing Enter.
7.
8. Applying Safe and Repeatable Modification Practices
4.1 Demo: Previewing and Validating Updates with find()
Fundamental Principle: Change data with intent, not with assumption.
Assumptions in data work are sneaky. Maybe each document is expected to have a specific field. One surprise later, and the careful plan ended up awry. Working with intention means confirming what is there, what will change, and what will stay before executing a single update.
Use find() before and after each modification
find() takes two parameters:
- The query filter — which documents to target
- The projection — which fields to return
// Pattern général : Avant → Modifier → Après
db.movies.find(filtre, projection).limit(n) // AVANT
// ... opération de modification ...
db.movies.find(filtre, projection).limit(n) // APRÈS
insertOne() and insertMany() for test documents
// Insérer un seul document de contrôle pour la validation
db.movies.insertOne({
title: "Mon Document Test",
year: 2025,
rated: "PG",
runtime: 90
})
// Insérer plusieurs documents (avec contrôle sur la gestion des erreurs)
db.movies.insertMany([
{ title: "Test A", year: 2020, rated: "G", runtime: 88 },
{ title: "Test B", year: 2021, rated: "PG", runtime: 95 },
{ title: "Test C", year: 2022, rated: "PG", runtime: 103 }
])
// Retourne les _id de tous les documents insérés
Demo 1 — insertOne() with before/after validation
const f1 = { title: "PS Demo Insert One" }
// Avant : confirmer l'absence
db.movies.find(f1, { _id: 1, title: 1, year: 1, rated: 1, runtime: 1 }).limit(1)
// Insérer
const r1 = db.movies.insertOne({
title: "PS Demo Insert One",
year: 2010,
rated: "PG",
runtime: 97,
genres: ["Training"]
})
print("Résultat insertOne :"); printjson(r1)
// Après : confirmer la présence
db.movies.find(f1, { _id: 1, title: 1, year: 1, rated: 1, runtime: 1 }).limit(1)
Demo 2 — insertMany() with scope previewed
const demo2Titles = ["PS Demo Insert Many A", "PS Demo Insert Many B", "PS Demo Insert Many C"]
const f2 = { title: { $in: demo2Titles } }
// Avant : 0 correspondances attendues
print("Correspondances prévues :", db.movies.countDocuments(f2))
// Insérer le batch
const r2 = db.movies.insertMany([
{ title: "PS Demo Insert Many A", year: 2012, rated: "G", runtime: 88, genres: ["Training"] },
{ title: "PS Demo Insert Many B", year: 2014, rated: "PG", runtime: 95, genres: ["Training"] },
{ title: "PS Demo Insert Many C", year: 2016, rated: "PG", runtime: 103, genres: ["Training"] }
])
print("Résultat insertMany :"); printjson(r2)
// Après : 3 documents présents
db.movies.find(f2, { _id: 1, title: 1, year: 1, rated: 1, runtime: 1 }).sort({ title: 1 })
Demo 3 — Protection against duplicates
const f3 = { title: "PS Demo Conditional Insert" }
// Vérifier l'existence avant d'insérer
const already3 = db.movies.countDocuments(f3)
print("Correspondances existantes :", already3)
if (already3 === 0) {
const r3 = db.movies.insertOne({
title: "PS Demo Conditional Insert",
year: 1999,
rated: "PG-13",
runtime: 101,
genres: ["Training"]
})
print("insertOne effectué :"); printjson(r3)
} else {
print("Insert ignoré pour éviter les doublons.")
}
// Confirmer
db.movies.find(f3, { _id: 1, title: 1, year: 1, rated: 1, runtime: 1 }).limit(1)
Demo 4 — Regex preview before insertion
const regex4 = /PS Demo.*Gold/i
const f4 = { title: regex4 }
// Avant : voir les correspondances actuelles
print("Correspondances regex actuelles :", db.movies.countDocuments(f4))
db.movies.find(f4, { _id: 1, title: 1, year: 1, rated: 1, runtime: 1 }).sort({ title: 1 })
// Insérer le nouveau document
const r4 = db.movies.insertOne({
title: "PS Demo Insert Gold Edition",
year: 2020,
rated: "PG",
runtime: 90,
genres: ["Training"]
})
print("Résultat insertOne :"); printjson(r4)
// Après
db.movies.find(f4, { _id: 1, title: 1, year: 1, rated: 1, runtime: 1 }).sort({ title: 1 })
Demo 5 — Secure repeatable insert with fixed _id
const fixedId5 = "ps-repeat-safe-demo"
const f5 = { _id: fixedId5 }
// Vérifier l'existence par _id
db.movies.find(f5, { _id: 1, title: 1, year: 1, rated: 1, runtime: 1 }).limit(1)
if (db.movies.countDocuments(f5) === 0) {
const r5 = db.movies.insertOne({
_id: fixedId5,
title: "PS Repeat Safe Insert",
year: 2011,
rated: "PG",
runtime: 91,
genres: ["Training"]
})
print("Résultat insertOne :"); printjson(r5)
} else {
print("Insert ignoré pour rester idempotent.")
}
// Confirmer
db.movies.find(f5, { _id: 1, title: 1, year: 1, rated: 1, runtime: 1 }).limit(1)
Takeaway: Each insertion — whether one document or several — must follow the same discipline: check first, insert only what is necessary, and validate later.
4.2 Demo: Simulating Updates with Dummy Fields
Instead of making a real irreversible change immediately, we first tag the target documents with a harmless temporary field. This field clearly marks records as part of a test. This allows you to review, count and analyze the affected group before pushing for real change.
Dummy field types (temporary markers)
| Flag type | Value example | Meaning |
|---|---|---|
| Boolean | flaggedForUpdate: true | Marked for update |
| Readable string | updateCheck: "dry-run-pass" | Simulation validated |
| Timestamp | simulateUpdate: new Date() | Simulation date |
| Simple integer | testOnly:1 | Test flag |
| Readiness flag | readyForLiveUpdate: false | Not ready yet |
These tags are non-destructive and easy to remove. You can repeat the process until you are confident that everything is correctly delineated.
Demo 1 — Dry-run marker with integer
Target action movies since 2007 and add testOnly:1.
const f1 = { genres: "Action", year: { $gte: 2007 } }
// Avant : compter la portée
print("Correspondances prévues :", db.movies.countDocuments(f1))
// → plus de 900 documents
db.movies.find(f1, { _id: 1, title: 1, year: 1, genres: 1, testOnly: 1 }).limit(1)
// Marquage dry-run
const r1 = db.movies.updateMany(f1, { $set: { testOnly: 1 } })
print("Résultat updateMany :"); printjson(r1)
// Après : vérifier que le tag est en place
const f1After = { genres: "Action", year: { $gte: 2007 }, testOnly: 1 }
db.movies.find(f1After, { _id: 1, title: 1, year: 1, testOnly: 1 }).limit(1)
Nothing in the original content has been altered. Only the marker field has been added.
Demo 2 — Flag readable with regex subset
R films, runtime 80-100 min, title containing “love”.
const f2 = { rated: "R", runtime: { $gte: 80, $lte: 100 }, title: /love/i }
// Avant
print("Correspondances prévues :", db.movies.countDocuments(f2))
// → 41 documents
db.movies.find(f2, { _id: 1, title: 1, rated: 1, runtime: 1, updateCheck: 1 }).limit(1)
// Marquage avec flag descriptif
const r2 = db.movies.updateMany(f2, { $set: { updateCheck: "dry-run-pass" } })
print("Résultat updateMany :"); printjson(r2)
// Après
const f2After = { rated: "R", runtime: { $gte: 80, $lte: 100 }, title: /love/i, updateCheck: "dry-run-pass" }
db.movies.find(f2After, { _id: 1, title: 1, updateCheck: 1 }).limit(1)
Demo 3 — Full flag with account validation
Films in English since 2000: more than 8,300 documents.
const f3 = { languages: "English", year: { $gte: 2000 } }
// Stocker le compte prévu pour comparaison ultérieure
const planned3 = db.movies.countDocuments(f3)
print("Correspondances prévues :", planned3)
// Marquage
const r3 = db.movies.updateMany(f3, { $set: { validOnly: 1 } })
print("Résultat updateMany :"); printjson(r3)
// Validation : le compte après marquage doit correspondre au compte prévu
const f3After = { languages: "English", year: { $gte: 2000 }, validOnly: 1 }
const flagged3 = db.movies.countDocuments(f3After)
print("Documents flaggés :", flagged3, "| Prévu :", planned3)
Demo 4 — Runtime classification via pipeline update with $switch
Tag movies with lengthClass (short/mid/long) using a pipeline update.
const f4 = { year: { $gte: 1990 }, runtime: { $type: "number" } }
const proj4 = { _id: 0, title: 1, runtime: 1, lengthClass: 1 }
// Avant : plus de 15 000 correspondances
print("Correspondances prévues :", db.movies.countDocuments(f4))
// Mise à jour avec pipeline et $switch
db.movies.updateMany(
f4,
[{
$set: {
lengthClass: {
$switch: {
branches: [
{ case: { $lt: ["$runtime", 80] }, then: "short" },
{ case: { $lt: ["$runtime", 120] }, then: "mid" }
],
default: "long"
}
}
}
}]
)
// Après : compter et prévisualiser chaque catégorie
["short", "mid", "long"].forEach(function(cls) {
const filterClass = { year: { $gte: 1990 }, runtime: { $type: "number" }, lengthClass: cls }
const c = db.movies.countDocuments(filterClass)
print("\n" + cls + " — count :", c)
db.movies.find(filterClass, proj4).limit(2).forEach(d => printjson(d))
})
// → short: ~1 000 | mid: ~11 000 | long: ~2 500
Cleaning with $unset
// Supprimer tous les champs dummy d'un seul coup
db.movies.updateMany(
{ genres: "Action", year: { $gte: 2007 }, testOnly: 1 },
{ $unset: { testOnly: "" } }
)
db.movies.updateMany(
{ rated: "R", runtime: { $gte: 80, $lte: 100 }, title: /love/i, updateCheck: "dry-run-pass" },
{ $unset: { updateCheck: "" } }
)
db.movies.updateMany(
{ languages: "English", year: { $gte: 2000 }, validOnly: 1 },
{ $unset: { validOnly: "" } }
)
db.movies.updateMany(
{ year: { $gte: 1990 }, lengthClass: { $in: ["short", "mid", "long"] } },
{ $unset: { lengthClass: "" } }
)
Takeaway: Updates with dummy fields are non-destructive and easy to remove. With a single $unset operation, one can roll back the entire test in seconds, leaving the data exactly as it was before experimenting.
4.3 Demo: Tracking Changes with Timestamps and Metadata
Key Principle: Tracking changes is just as important as making them.
MongoDB provides specialized operators to store the history behind each update.
Tracking operators
| Operator / Field | Description | Example |
|---|---|---|
$currentDate: { lastModified: true } | Automatic timestamp at update time | lastModified: ISODate("2025-06-20T...") |
$set: { updatedBy: "..." } | Who made the change | updatedBy: "script-cleanup" |
$set: { changeReason: "..." } | Why the modification | changeReason: "rating standardization" |
$set: { updateSource: "..." } | Where does the change come from | updateSource: "batch" or "manual" |
$set: { updateBatch: "..." } | Change Set ID | updateBatch: "batch-2025-06-20" |
$set: { statusChangeNote: "..." } | State Change Note | statusChangeNote: "changed from draft to published" |
$setOnInsert: { createdAt: new Date() } | Creation timestamp (only when inserting via upsert) | createdAt: ISODate("2025-06-20T...") |
These fields make the data self-documenting: at a glance, we see not only what has changed, but also how and why.
Demo 1 — Batch audit with rich metadata
PG-13 films since 2015 (33 documents).
const f1 = { rated: "PG-13", year: { $gte: 2015 } }
print("Correspondances prévues :", db.movies.countDocuments(f1))
// → 33
// Avant : lastModified et updatedBy ne sont pas encore renseignés
db.movies.find(f1, { _id: 1, title: 1, rated: 1, year: 1, lastModified: 1, updatedBy: 1 }).limit(1)
// Mise à jour avec audit et horodatage automatique
db.movies.updateMany(
f1,
{
$set: {
updatedBy: "audit-demo",
changeReason: "visibility tag",
updateSource: "batch"
},
$currentDate: { lastModified: true }
}
)
// → 33 documents modifiés
// Après : les métadonnées d'audit sont en place + timestamp frais
db.movies.find(f1, { _id: 1, title: 1, updatedBy: 1, lastModified: 1, changeReason: 1, updateSource: 1 }).limit(1)
Demo 2 — Pattern upsert with createdAt and lastModified
Create if absent, always refresh lastModified.
const key = "ps-audit-upsert-demo"
// Avant : document absent
db.movies.find(
{ _id: key },
{ _id: 1, title: 1, createdAt: 1, lastModified: 1, updatedBy: 1 }
).forEach(d => printjson(d))
// Upsert avec audit complet
db.movies.updateOne(
{ _id: key },
{
$set: {
title: "Audit Upsert Demo",
updatedBy: "audit-upsert",
updateSource: "upsert"
},
$setOnInsert: {
createdAt: new Date(),
year: 2025
},
$currentDate: { lastModified: true }
},
{ upsert: true }
)
// Après : nouveau document avec createdAt + lastModified + métadonnées
db.movies.find(
{ _id: key },
{ _id: 1, title: 1, year: 1, createdAt: 1, lastModified: 1, updatedBy: 1, updateSource: 1 }
).limit(1).forEach(d => printjson(d))
Takeaway: These two patterns — targeted audits with rich metadata, and secure upserts with creation and modification tracking — are reliable building blocks for keeping updates traceable and reversible in MongoDB.
4.4 Communicating Before Modifying Shared Datasets
Why communication is essential
When you modify data, you modify what people see and depend on. Even a small change can move a KPI, trigger an alert or make a dashboard appear incorrect. Sending a short message before making a change turns surprises into plans, gives others the chance to review, and keeps shared data stable.
What to share before an update
| Element | Description |
|---|---|
| Targeted documents | Paste the exact filter so anyone can copy it into find() |
| Fields modified | Give a small before/after example so that reviewers can visualize the change |
| Rationale | One or two sentences linking the change to the business need — not just the syntax |
| Test Method | Show how it was tested (preview with find() or dry-run with flag) |
Risk Levels and Communication Expectations
| Risk level | Scenario | Communication |
|---|---|---|
| 🟢 Weak | Updating a personal copy | Optional |
| 🟢 Weak | Fixed typos on 1-2 documents | Optional (a little reminder doesn’t hurt) |
| 🟡 Medium | Editing 100+ documents | Yes — notify, volume multiplies impact |
| 🔴 High | Deletion or replacement of documents | Absolutely — alert the right people |
| 🔴 High | Editing shared production data | Absolutely — ideally with a second reviewer and a rollback plan |
General rule: The bigger the change, the sooner the message, the wider the audience.
Security checklist before an update (5 steps)
☐ 1. Ai-je documenté le filtre et la logique de mise à jour clairement ?
→ Doit être lisible sans décodage par n'importe qui.
☐ 2. Ai-je testé le filtre avec find() ou un dry-run ?
→ La portée doit correspondre exactement aux documents qu'on prévoit de changer.
☐ 3. Ce changement pourrait-il impacter les dashboards ou les processus d'autres équipes ?
→ Confirmer que les effets sont isolés — rien ne doit se propager de façon inattendue.
☐ 4. Ai-je partagé le plan de mise à jour avec les bonnes personnes ?
(analytics, propriétaires d'application, équipe support)
→ Doit être revu et reconnu avant d'exécuter.
☐ 5. Suis-je la bonne personne pour effectuer cette mise à jour ?
(j'ai l'accès, le contexte, et la disponibilité pour surveiller les résultats)
→ Doit pouvoir être exécuté et surveillé sans lacunes.
These five quick steps, each of which leads naturally to the next, typically take a minute and can save an hour correcting the consequences.
The difference between a good analyst and a great analyst
- Good analyst: Knows how to modify data. Knows how to find the right documents, apply the right change, and keep the database healthy.
- Excellent analyst: Edits with transparency. Shows exactly what he plans to change and how he tested it. This habit turns a technical change into a shared decision and makes modification practices repeatable.
9. Operator Quick Reference
Update operators (update operators)
| Operator | Syntax | Description |
|---|---|---|
$set | { $set: { field: value } } | Add or modify a field |
$unset | { $unset: { field: "" } } | Delete a field |
$rename | { $rename: { oldName: "newName" } } | Rename a field |
$inc | { $inc: { field: n } } | Increment by n (positive or negative) |
$currentDate | { $currentDate: { field: true } } | Automatic timestamp |
$setOnInsert | { $setOnInsert: { field: value } } | Value only during an insert (upsert) |
Filter operators (query operators)
| Operator | Description | Example |
|---|---|---|
$gt / $gte | Greater than / greater than or equal to | { year: { $gte: 2000 } } |
$lt / $lte | Less than / less than or equal | { runtime: { $lt: 60 } } |
$exists | Existence of the field | { rated: { $exists: false } } |
$in | Value in a list | { title: { $in: ["A", "B"] } } |
$type | Field data type | { runtime: { $type: "number" } } |
Regex /pattern/i | Case-insensitive regular expression | { title: /gold/i } |
MongoDB Methods (summary)
| Method | Description |
|---|---|
find(filter, projection) | Read documents |
findOne(filter, projection) | Read the first corresponding document |
countDocuments(filter) | Count matching documents |
insertOne(document) | Insert a document |
insertMany([...documents]) | Insert multiple documents |
updateOne(filter, update) | Update a document |
updateMany(filter, update) | Update multiple documents |
replaceOne(filter, replacement) | Replace an entire document |
deleteOne(filter) | Delete a document |
deleteMany(filter) | Delete multiple documents |
Dot notation for nested fields
// Accéder à un champ imbriqué dans un filtre
{ "awards.wins": { $gt: 10 } }
// Mettre à jour un champ imbriqué
{ $set: { "tomatoes.viewer.rating": 4.5 } }
// Aller encore plus profond
{ $inc: { "tomatoes.viewer.numReviews": 1 } }
10. Demo files
Module 1 — 01/demos/demo.txt
Setting up and checking the environment.
use sample_mflix
show collections
db.movies.findOne()
db
Module 2 — 02/demos/demo1.txt — updateOne()
Demonstrations of updateOne() on the movies collection:
- Change the rating of “The Princess Diaries” (G → PG-13)
- Update year and rated simultaneously for “The Net”
- Filter with title + year for “The Negotiator” (1998)
- Target via
_idfor a movie with runtime > 220 →isOutlier: true - Rewrite the
languagestable of “The Terminal”
Module 2 — 02/demos/demo2.txt — updateMany()
Demonstrations of updateMany():
- Add
decade: "1980s"to all movies from 1980-1989 - Add
rated: "Not Rated"where theratedfield is missing ($exists: false) - Replace the genre “Documentary” with “Docu” in the
genrestable - Add
isShort: truefor movies withruntime < 60
Module 2 — 02/demos/demo3.txt — Update operators
Demonstrations of the $set, $unset, $rename, $inc operators:
$set— Change theratedof “Catch Me If You Can” (PG-13 → R)$unset— Removeplotfield from “Catch Me If You Can”$rename— Renameplot→fullPloton an action movie$inc— Increment theruntimeof “The Terminal” by 5 minutes (128 → 133)- Combination
$set + $inc— Addtagged: trueand incrementruntimeby 10
Module 2 — 02/demos/demo4.txt — Nested fields
Dot notation update demonstrations on “The Godfather”:
"awards.wins"— Change from 33 to 55"tomatoes.viewer.rating"— Change from 4.4 to 4.5"tomatoes.critic.confidence"— Add a new field with value “High”$inc "tomatoes.viewer.numReviews"— Increment by 1 (73 → 74)
Module 2 — 02/demos/demo5.txt — Checking the results
Result Object Analysis Demonstrations:
- Store result in
result1, inspect all properties (acknowledged,matchedCount,modifiedCount,upsertedCount,upsertedId) - Handle the case of a filter that matches nothing (
matchedCount: 0) + conditional logic
Module 3 — 03/demos/demo1.txt — replaceOne()
Demonstrations of replaceOne():
- Restructuring of “The Negotiator” — create
releaseobject, removeawardsandtomatoes - Reset of “The Net” — keep only
titleandyear - Upsert of “Pluralsight Demo Movie” — insert if absent, replace if present (
upsert: true)
Module 3 — 03/demos/demo2.txt — deleteOne() / deleteMany()
Removal demonstrations:
deleteOne— Delete “Pluralsight Demo Movie”deleteMany— Delete all movies withruntime: 60(61 documents)- Pattern with variables —
countDocuments()beforedeleteMany()for films before 1920 (18 documents) - Regex — Remove movies whose title contains “gold” case insensitive (56 documents)
Module 4 — 04/demos/demo1.txt — Insertion and validation
Demonstrations of insertOne() / insertMany() with before/after pattern:
- simple
insertOne()with validation (f1 = { title: "PS Demo Insert One" }) insertMany()with filter$inand 3 batch documents- Guard against duplicates with
countDocuments()before insertion - Regex preview before insertion (
/PS Demo.*Gold/i) - Idempotent insert with fixed
_id("ps-repeat-safe-demo") - Cleanup —
deleteManyon all demo documents
Module 4 — 04/demos/demo2.txt — Simulation with dummy fields
Dry-run pattern demonstrations:
testOnly: 1— Action films since 2007 (900+ documents)updateCheck: "dry-run-pass"— R movies, runtime 80-100, title containing “love” (41 documents)validOnly: 1— English films since 2000 (8,300+ documents) with account validationlengthClassvia pipeline$switch— Short/mid/long classification (15,000+ documents)- Cleanup —
$unseton all dummy fields
Module 4 — 04/demos/demo3.txt — Timestamps and metadata
Change Tracking Demonstrations:
- Batch audit — PG-13 films since 2015 (33 documents) with
updatedBy,changeReason,updateSource,$currentDate: lastModified - Upsert with audit — Creation with
$setOnInsert: { createdAt: new Date() }+$currentDate: { lastModified: true }+$setfor metadata - Cleanup —
$unsetof audit fields,deleteOneof document upsert demo
Search Terms
modify · data · analysis · mongodb · nosql · databases · sql · update · field · fields · nested · operators · documents · delete · four · operations · syntax · updates · validation · via · change · deciding · deleteone · demo1.txt