There are several common strategies for document versioning. The
strategy you select will depend on the trade-offs you want to make.
Please note that MongoDB does not have any support for triggers. So a
few of these methods will require that you be able to do multiple
writes.
===
Strategy 1: embed history
===
In theory, you can embed the history of a document inside of the
document itself. This can even be done atomically.
> db.docs.save( { _id : 1, text : "Original Text" } )
> var doc = db.docs.findOne()
> db.docs.update( {_id: doc._id}, { $set : { text : 'New Text' }, $push : { hist : doc.text } } )
> db.docs.find()
{ "_id" : 1, "hist" : [ "Original Text" ], "text" : "New Text" }
For even more atomicity, you can use findAndModify:
> db.docs.findAndModify( {query:{_id:1}, update: { $set : { text : 'New Text' }, $push : { hist : "Original Text" } }, new : true} )
===
Strategy 2: write history to separate collection
===
> db.docs.save( { _id : 1, text : "Original Text" } )
> var doc = db.docs.findOne()
> db.docs_hist.insert ( { orig_id : doc._id, ts : Math.round((new Date()).getTime() / 1000), data : doc } )
> db.docs.update( {_id:doc._id}, { $set : { text : 'New Text' } } )
Here you'll see that I do two writes. One to the master collection and
one to the history collection.
To get fast history lookup, just grab the original ID:
> db.docs_hist.ensureIndex( { orig_id : 1, ts : 1 })
> db.docs_hist.find( { orig_id : 1 } ).sort( { ts : -1 } )
-----
Both strategies can be enhanced by storing only the diffs.
There are several small variants here, but they tend to fall under one
of these two themes: embed or separate collection.
Embedding:
+ atomic change (especially with findAndModify)
- can result in large documents, may break the 16MB limit
- probably have to enhance code to avoid returning full hist when not
necessary
Separate collection:
+ easier to write queries
- not atomic, needs two operations and Mongo doesn't have
transactions
- more storage space (extra indexes on original docs)
Hopefully that gets you working in the right direction.
- Gates