Intermediate

Modify Data for Analysis in MongoDB

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 c...

Dataset used: sample_mflix (collection movies)


Table of Contents

  1. Module 1 — Deciding When and How to Modify Data in MongoDB (17m 39s)
  1. Module 2 — Performing Targeted Updates Using Structured Commands (22m 39s)
  1. Module 3 — Replacing and Removing Documents Safely (13m 30s)
  1. Module 4 — Applying Safe and Repeatable Modification Practices (25m 5s)
  1. Quick operator reference
  2. Demo files

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

ScenarioDescriptionExample
Inconsistent valuesStandardize mixed values ​​for the same fieldThe rating field contains “PG-13”, “pg-13”, “Pg13” → normalize everything to “PG-13”
Missing valuesFill in or report a missing fieldruntime is null → fill with a reliable value and add runtimeWasMissing: true
Inconsistent formattingStandardize date or identifier structuresDates in numeric vs alphabetical format → convert everything to ISO 8601
EnrichmentAdd fields for analysis or exportAdd 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

CriterionRead operationsWrite operations
Impact on dataNoneDirect — modifies content
ReversibilityNothing to cancelOften non-reversible (without backup)
Re-execution securityAlways safeSometimes safe, not always
Risk levelLowHigh

Read operations

OrderDescription
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

OrderDescription
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

QuestionIf 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

  1. In the Atlas interface, confirm that the example dataset is loaded (green banner)
  2. In the left sidebar, under DATABASE, click Data Explorer
  3. Three databases are visible: admin, local, sample_mflix
  4. The main playground is sample_mflix
  5. 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

  1. From the Atlas cluster screen, click Connect
  2. Choose Shell
  3. Copy the generated connection string
  4. In the terminal, paste and execute the command
  5. Enter password when prompted
  6. 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:

PropertyDescription
acknowledgedtrue if the command was processed successfully
matchedCountNumber of documents matching the filter
modifiedCountNumber of documents actually modified
upsertedCountNumber of documents inserted (0 if no upsert)
upsertedIdnull if no upsert

Reminder: An upsert is 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

OperatorRoleUse cases
$setAdd or modify a fieldCorrect a value, add a new field
$unsetDelete a fieldRemove an obsolete or unnecessary field
$renameRename a fieldHarmonize the diagram without manually copying
$incIncrement a numeric valueCounters, 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

CriterionupdateOne()replaceOne()
ScopeSpecific fieldsEntire document
Fields not mentionedPreservedDeleted
Use casesSmall targeted correctionsComplete restructuring
Risk of lossLowHigh if poorly planned
Planning RequiredMinimalImportant

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)

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:

  1. Store the count of matching documents in a variable before deleting
  2. Store the delete result in a variable to check deletedCount
  3. 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:

  1. The query filter — which documents to target
  2. 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 typeValue exampleMeaning
BooleanflaggedForUpdate: trueMarked for update
Readable stringupdateCheck: "dry-run-pass"Simulation validated
TimestampsimulateUpdate: new Date()Simulation date
Simple integertestOnly:1Test flag
Readiness flagreadyForLiveUpdate: falseNot 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 / FieldDescriptionExample
$currentDate: { lastModified: true }Automatic timestamp at update timelastModified: ISODate("2025-06-20T...")
$set: { updatedBy: "..." }Who made the changeupdatedBy: "script-cleanup"
$set: { changeReason: "..." }Why the modificationchangeReason: "rating standardization"
$set: { updateSource: "..." }Where does the change come fromupdateSource: "batch" or "manual"
$set: { updateBatch: "..." }Change Set IDupdateBatch: "batch-2025-06-20"
$set: { statusChangeNote: "..." }State Change NotestatusChangeNote: "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

ElementDescription
Targeted documentsPaste the exact filter so anyone can copy it into find()
Fields modifiedGive a small before/after example so that reviewers can visualize the change
RationaleOne or two sentences linking the change to the business need — not just the syntax
Test MethodShow how it was tested (preview with find() or dry-run with flag)

Risk Levels and Communication Expectations

Risk levelScenarioCommunication
🟢 WeakUpdating a personal copyOptional
🟢 WeakFixed typos on 1-2 documentsOptional (a little reminder doesn’t hurt)
🟡 MediumEditing 100+ documentsYes — notify, volume multiplies impact
🔴 HighDeletion or replacement of documentsAbsolutely — alert the right people
🔴 HighEditing shared production dataAbsolutely — 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)

OperatorSyntaxDescription
$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)

OperatorDescriptionExample
$gt / $gteGreater than / greater than or equal to{ year: { $gte: 2000 } }
$lt / $lteLess than / less than or equal{ runtime: { $lt: 60 } }
$existsExistence of the field{ rated: { $exists: false } }
$inValue in a list{ title: { $in: ["A", "B"] } }
$typeField data type{ runtime: { $type: "number" } }
Regex /pattern/iCase-insensitive regular expression{ title: /gold/i }

MongoDB Methods (summary)

MethodDescription
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:

  1. Change the rating of “The Princess Diaries” (G → PG-13)
  2. Update year and rated simultaneously for “The Net”
  3. Filter with title + year for “The Negotiator” (1998)
  4. Target via _id for a movie with runtime > 220 → isOutlier: true
  5. Rewrite the languages table of “The Terminal”

Module 2 — 02/demos/demo2.txt — updateMany()

Demonstrations of updateMany():

  1. Add decade: "1980s" to all movies from 1980-1989
  2. Add rated: "Not Rated" where the rated field is missing ($exists: false)
  3. Replace the genre “Documentary” with “Docu” in the genres table
  4. Add isShort: true for movies with runtime < 60

Module 2 — 02/demos/demo3.txt — Update operators

Demonstrations of the $set, $unset, $rename, $inc operators:

  1. $set — Change the rated of “Catch Me If You Can” (PG-13 → R)
  2. $unset — Remove plot field from “Catch Me If You Can”
  3. $rename — Rename plotfullPlot on an action movie
  4. $inc — Increment the runtime of “The Terminal” by 5 minutes (128 → 133)
  5. Combination $set + $inc — Add tagged: true and increment runtime by 10

Module 2 — 02/demos/demo4.txt — Nested fields

Dot notation update demonstrations on “The Godfather”:

  1. "awards.wins" — Change from 33 to 55
  2. "tomatoes.viewer.rating" — Change from 4.4 to 4.5
  3. "tomatoes.critic.confidence" — Add a new field with value “High”
  4. $inc "tomatoes.viewer.numReviews" — Increment by 1 (73 → 74)

Module 2 — 02/demos/demo5.txt — Checking the results

Result Object Analysis Demonstrations:

  1. Store result in result1, inspect all properties (acknowledged, matchedCount, modifiedCount, upsertedCount, upsertedId)
  2. Handle the case of a filter that matches nothing (matchedCount: 0) + conditional logic

Module 3 — 03/demos/demo1.txt — replaceOne()

Demonstrations of replaceOne():

  1. Restructuring of “The Negotiator” — create release object, remove awards and tomatoes
  2. Reset of “The Net” — keep only title and year
  3. Upsert of “Pluralsight Demo Movie” — insert if absent, replace if present (upsert: true)

Module 3 — 03/demos/demo2.txt — deleteOne() / deleteMany()

Removal demonstrations:

  1. deleteOne — Delete “Pluralsight Demo Movie”
  2. deleteMany — Delete all movies with runtime: 60 (61 documents)
  3. Pattern with variablescountDocuments() before deleteMany() for films before 1920 (18 documents)
  4. 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:

  1. simple insertOne() with validation (f1 = { title: "PS Demo Insert One" })
  2. insertMany() with filter $in and 3 batch documents
  3. Guard against duplicates with countDocuments() before insertion
  4. Regex preview before insertion (/PS Demo.*Gold/i)
  5. Idempotent insert with fixed _id ("ps-repeat-safe-demo")
  6. CleanupdeleteMany on all demo documents

Module 4 — 04/demos/demo2.txt — Simulation with dummy fields

Dry-run pattern demonstrations:

  1. testOnly: 1 — Action films since 2007 (900+ documents)
  2. updateCheck: "dry-run-pass" — R movies, runtime 80-100, title containing “love” (41 documents)
  3. validOnly: 1 — English films since 2000 (8,300+ documents) with account validation
  4. lengthClass via pipeline $switch — Short/mid/long classification (15,000+ documents)
  5. Cleanup$unset on all dummy fields

Module 4 — 04/demos/demo3.txt — Timestamps and metadata

Change Tracking Demonstrations:

  1. Batch audit — PG-13 films since 2015 (33 documents) with updatedBy, changeReason, updateSource, $currentDate: lastModified
  2. Upsert with audit — Creation with $setOnInsert: { createdAt: new Date() } + $currentDate: { lastModified: true } + $set for metadata
  3. Cleanup$unset of audit fields, deleteOne of 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

Interested in this course?

Contact us to book it or get a custom training plan for your team.