$ lexprog.com

// notes from an old coder -- php, databases, and the occasional rant

[November 17, 2025] MongoDB

MongoDB Versioned Documents

MongoDB Versioned Documents

────────────────────────────────────────────────────────

MongoDB Versioned Documents

Tip: Version Field

$post = [
    'title' => 'Hello',
    'version' => 1,
    'history' => [
        ['version' => 0, 'title' => 'Draft', 'changed_at' => now()],
    ],
];

Gotcha: History Growth

Unbounded history arrays can exceed the 16MB document limit. Limit history entries.

Tip: Separate History Collection

$history->insertOne([
    'document_id' => $postId,
    'version' => 1,
    'data' => $previousData,
]);

Gotcha: Restore from History

$previous = $history->findOne(['document_id' => $postId, 'version' => 1]);
$collection->updateOne(['_id' => $postId], ['$set' => $previous['data']]);

Tip: Optimistic Locking

$collection->updateOne(
    ['_id' => $id, 'version' => $currentVersion],
    ['$set' => ['title' => $newTitle], '$inc' => ['version' => 1]]
);

Gotcha: Concurrent Updates

Without optimistic locking, concurrent updates can overwrite each other.

Tip: Embed or Reference? The 80/20 Rule

If you always access data together, embed it. If you access it independently, reference it. The 16MB document size limit is the hard boundary — stay under 1MB for most documents.

Tip: Index Your Query Patterns, Not All Fields

Creating indexes on every field wastes RAM. Use explain() to find in-memory sorts and collection scans. Index only what your actual queries filter on.

Gotcha: No Transaction Rollback for Index Builds

Building an index on a large collection can take hours. If it fails midway, the partial index is silently discarded. Plan index builds during maintenance windows.

Senior Insight

Document versioning in MongoDB is straightforward — add a version field to each document and include it in update queries with $inc. I've used optimistic concurrency control with versioned documents to prevent lost updates in concurrent environments. MongoDB doesn't provide automatic versioning like CouchDB, but the pattern is trivial to implement: updateOne({_id: id, version: currentVersion}, {$set: {...}, $inc: {version: 1}}) and check modifiedCount === 1.

Source: MongoDB Developer Center (https://www.mongodb.com/developer/), MongoDB Engineering Blog (https://www.mongodb.com/blog/channel/engineering-blog), Studio 3T Blog (https://studio3t.com/blog/)

────────────────────────────────────────────────────────
<-- back to posts