diff --git a/bin/migrate_mongodb_flatten_opdata b/bin/migrate_mongodb_flatten_opdata new file mode 100755 index 00000000..35b47c00 --- /dev/null +++ b/bin/migrate_mongodb_flatten_opdata @@ -0,0 +1,24 @@ +#!/usr/bin/env node + +# The MongoDb driver used to create an unnecessary "opData" key in op documents. +# Future ops now do not create this key. This script fixes all existing ops. + +require('coffee-script'); + +var createdb = require('../src/server/db'); +var options = require('./options'); +if (options.db.type !== 'mongo') { + console.error('You must configure your server to use mongodb before using this script'); + process.exit(1); +} + +var db = createdb(options.db); +db.migrateFlattenOpData(function(error) { + if(error) { + throw new Error(error.toString()); + } else { + console.log("DB migrated successfully"); + } + db.close(); +}); + diff --git a/src/server/db/mongo.coffee b/src/server/db/mongo.coffee index 4168726f..e8ba1181 100644 --- a/src/server/db/mongo.coffee +++ b/src/server/db/mongo.coffee @@ -107,7 +107,17 @@ module.exports = MongoDb = (options) -> console.warn "failed to get ops for #{docName}: #{err}" if err return callback? err if err - callback? null, (doc.opData for doc in docs) + result = [] + for doc in docs + # This is to support an old schema where ops were stored within an + # "opData" object. + if doc.opData + result.push doc.opData + else + delete doc._id + result.push doc + + callback? null, result # Write an op to a document. # @@ -125,9 +135,8 @@ module.exports = MongoDb = (options) -> return callback? err if err doc = - opData: - op: opData.op - meta: opData.meta + op: opData.op + meta: opData.meta if options.opsCollectionPerDoc doc._id = opData.v @@ -201,6 +210,37 @@ module.exports = MongoDb = (options) -> opsCollection.remove { '_id.doc': docName }, (err, count) -> callback? err + flattenOpDataCollection = (name, callback) -> + client.collection name, (err, collection) -> + collection.update {}, {$rename: {"opData.op": "op", "opData.meta": "meta"}}, {multi: true}, (err) -> + return callback(err) if err + collection.update {}, {$unset: {opData: ""}}, {multi: true}, (err) -> + callback(err) + + # A migration to flatten the unnecessary "opdata" key + @migrateFlattenOpData = (callback = ->) -> + if options.opsCollectionPerDoc + client.collection 'docs', (err, docsCollection) -> + return callback(err) if err + + docCount = 0 + docDoneCount = 0 + + docsCollection.find({}).each (err, doc) -> + return callback(err) if err + return if not doc?._id + docCount += 1 + flattenOpDataCollection opsCollectionForDoc(doc._id), (err) -> + return callback(err) if err + docDoneCount += 1 + if docDoneCount == docCount + callback() + + else + flattenOpDataCollection 'ops', callback + + + # Close the connection to the database @close = -> client.close()