Update and Delete Operations

Modifying data in a distributed system is fundamentally different from a single-node RDBMS. In MongoDB, you must understand Atomicity and Write Concern to ensure data integrity without sacrificing performance.

1. First Principles: Atomicity

In MongoDB, a write operation is atomic on the level of a single document, even if the operation modifies multiple embedded documents within it.

  • Single Document: Atomic. If you update 10 fields in one document, either all 10 update or none do.
  • Multiple Documents: Not atomic by default. If updateMany() hits 100 documents and the server crashes after 50, only 50 are updated. (Multi-document transactions exist but come with a performance cost).

Interactive: Atomicity Visualizer

See how a single document update is “All or Nothing”, while multi-document updates can leave the system in a partial state if interrupted.

Ready

2. Updating Documents

The Operators

Instead of sending the full document back to the server (which risks race conditions), we send Update Operators.

  • $set: Updates the value of a field.
  • $inc: Increments a numerical value.
  • $unset: Deletes a field.
  • $currentDate: Sets a field to the current date.

The Power of Upserts

An Upsert (Update + Insert) is a conditional operation:

  1. Attempt to find a document matching the filter.
  2. If found, update it.
  3. If not found, create a new document using the filter and update operations.

This is critical for idempotent counters and “first-seen” logic.

Interactive: Upsert Logic

Visualize the decision flow of an Upsert operation.

?
Checking...

Code Examples

Java

import com.mongodb.client.model.UpdateOptions;
import static com.mongodb.client.model.Filters.*;
import static com.mongodb.client.model.Updates.*;

public void updateDocs(MongoCollection<Document> collection) {
    // 1. Atomic Increment
    collection.updateOne(eq("name", "Canvas"), inc("stock", -1));

    // 2. Update Many
    collection.updateMany(lt("stock", 10), set("status", "LOW_STOCK"));

    // 3. Upsert: Track page views
    UpdateOptions options = new UpdateOptions().upsert(true);
    collection.updateOne(
        eq("page", "/home"),
        inc("views", 1),
        options
    );
}

Go

func UpdateDocs(ctx context.Context, coll *mongo.Collection) {
    // 1. Atomic Increment
    _, err := coll.UpdateOne(
        ctx,
        bson.D{{"name", "Canvas"}},
        bson.D{{"$inc", bson.D{{"stock", -1}}}},
    )

    // 2. Upsert
    opts := options.Update().SetUpsert(true)
    filter := bson.D{{"page", "/home"}}
    update := bson.D{{"$inc", bson.D{{"views", 1}}}}

    _, err = coll.UpdateOne(ctx, filter, update, opts)
}

3. Deleting Documents

Deletes are straightforward but permanent. Always verify your filter with a find() (dry run) before executing a deleteMany().

// Java
collection.deleteOne(eq("_id", new ObjectId("...")));
collection.deleteMany(lt("created_at", "2022-01-01"));
// Go
coll.DeleteOne(ctx, bson.D{{"_id", id}})
coll.DeleteMany(ctx, bson.D{{"created_at", bson.D{{"$lt", "2022-01-01"}}}})

4. Under the Hood: Write Concern

When does the application get an “OK” response? This is controlled by Write Concern.

  • w: 1 (Default): Acknowledged by the Primary only. Fast, but data could be lost if the Primary crashes before replicating.
  • w: majority: Acknowledged by the Primary and a majority of Secondaries. High durability, higher latency.
  • j: true: Acknowledged only after writing to the on-disk Journal. Highest durability.

Write Concern Simulator

Visualize the latency cost of durability.

P
S1
S2
Latency: 0ms Ready

5. Visualizing Replication

sequenceDiagram
  participant Client
  participant Primary
  participant Secondary1
  participant Secondary2

  Client->>Primary: Insert (w: majority)
  Primary->>Primary: Write to Journal
  par Replication
      Primary->>Secondary1: Replicate (Oplog)
      Primary->>Secondary2: Replicate (Oplog)
  end
  Secondary1-->>Primary: Ack
  Note right of Primary: Majority Reached (P + S1)
  Primary-->>Client: Success (OK)
  Secondary2-->>Primary: Ack

[!IMPORTANT] Use w: majority for critical data. Financial transactions, user registrations, and audit logs should always survive a primary failover.