diff options
Diffstat (limited to 'src/mongo/shell/collection.js')
| -rw-r--r-- | src/mongo/shell/collection.js | 892 |
1 files changed, 892 insertions, 0 deletions
diff --git a/src/mongo/shell/collection.js b/src/mongo/shell/collection.js new file mode 100644 index 00000000000..342f07b936f --- /dev/null +++ b/src/mongo/shell/collection.js @@ -0,0 +1,892 @@ +// @file collection.js - DBCollection support in the mongo shell +// db.colName is a DBCollection object +// or db["colName"] + +if ( ( typeof DBCollection ) == "undefined" ){ + DBCollection = function( mongo , db , shortName , fullName ){ + this._mongo = mongo; + this._db = db; + this._shortName = shortName; + this._fullName = fullName; + + this.verify(); + } +} + +DBCollection.prototype.verify = function(){ + assert( this._fullName , "no fullName" ); + assert( this._shortName , "no shortName" ); + assert( this._db , "no db" ); + + assert.eq( this._fullName , this._db._name + "." + this._shortName , "name mismatch" ); + + assert( this._mongo , "no mongo in DBCollection" ); +} + +DBCollection.prototype.getName = function(){ + return this._shortName; +} + +DBCollection.prototype.help = function () { + var shortName = this.getName(); + print("DBCollection help"); + print("\tdb." + shortName + ".find().help() - show DBCursor help"); + print("\tdb." + shortName + ".count()"); + print("\tdb." + shortName + ".copyTo(newColl) - duplicates collection by copying all documents to newColl; no indexes are copied."); + print("\tdb." + shortName + ".convertToCapped(maxBytes) - calls {convertToCapped:'" + shortName + "', size:maxBytes}} command"); + print("\tdb." + shortName + ".dataSize()"); + print("\tdb." + shortName + ".distinct( key ) - eg. db." + shortName + ".distinct( 'x' )"); + print("\tdb." + shortName + ".drop() drop the collection"); + print("\tdb." + shortName + ".dropIndex(name)"); + print("\tdb." + shortName + ".dropIndexes()"); + print("\tdb." + shortName + ".ensureIndex(keypattern[,options]) - options is an object with these possible fields: name, unique, dropDups"); + print("\tdb." + shortName + ".reIndex()"); + print("\tdb." + shortName + ".find([query],[fields]) - query is an optional query filter. fields is optional set of fields to return."); + print("\t e.g. db." + shortName + ".find( {x:77} , {name:1, x:1} )"); + print("\tdb." + shortName + ".find(...).count()"); + print("\tdb." + shortName + ".find(...).limit(n)"); + print("\tdb." + shortName + ".find(...).skip(n)"); + print("\tdb." + shortName + ".find(...).sort(...)"); + print("\tdb." + shortName + ".findOne([query])"); + print("\tdb." + shortName + ".findAndModify( { update : ... , remove : bool [, query: {}, sort: {}, 'new': false] } )"); + print("\tdb." + shortName + ".getDB() get DB object associated with collection"); + print("\tdb." + shortName + ".getIndexes()"); + print("\tdb." + shortName + ".group( { key : ..., initial: ..., reduce : ...[, cond: ...] } )"); + print("\tdb." + shortName + ".insert(obj)"); + print("\tdb." + shortName + ".mapReduce( mapFunction , reduceFunction , <optional params> )"); + print("\tdb." + shortName + ".remove(query)"); + print("\tdb." + shortName + ".renameCollection( newName , <dropTarget> ) renames the collection."); + print("\tdb." + shortName + ".runCommand( name , <options> ) runs a db command with the given name where the first param is the collection name"); + print("\tdb." + shortName + ".save(obj)"); + print("\tdb." + shortName + ".stats()"); + print("\tdb." + shortName + ".storageSize() - includes free space allocated to this collection"); + print("\tdb." + shortName + ".totalIndexSize() - size in bytes of all the indexes"); + print("\tdb." + shortName + ".totalSize() - storage allocated for all data and indexes"); + print("\tdb." + shortName + ".update(query, object[, upsert_bool, multi_bool]) - instead of two flags, you can pass an object with fields: upsert, multi"); + print("\tdb." + shortName + ".validate( <full> ) - SLOW");; + print("\tdb." + shortName + ".getShardVersion() - only for use with sharding"); + print("\tdb." + shortName + ".getShardDistribution() - prints statistics about data distribution in the cluster"); + print("\tdb." + shortName + ".getSplitKeysForChunks( <maxChunkSize> ) - calculates split points over all chunks and returns splitter function"); + return __magicNoPrint; +} + +DBCollection.prototype.getFullName = function(){ + return this._fullName; +} +DBCollection.prototype.getMongo = function(){ + return this._db.getMongo(); +} +DBCollection.prototype.getDB = function(){ + return this._db; +} + +DBCollection.prototype._dbCommand = function( cmd , params ){ + if ( typeof( cmd ) == "object" ) + return this._db._dbCommand( cmd ); + + var c = {}; + c[cmd] = this.getName(); + if ( params ) + Object.extend( c , params ); + return this._db._dbCommand( c ); +} + +DBCollection.prototype.runCommand = DBCollection.prototype._dbCommand; + +DBCollection.prototype._massageObject = function( q ){ + if ( ! q ) + return {}; + + var type = typeof q; + + if ( type == "function" ) + return { $where : q }; + + if ( q.isObjectId ) + return { _id : q }; + + if ( type == "object" ) + return q; + + if ( type == "string" ){ + if ( q.length == 24 ) + return { _id : q }; + + return { $where : q }; + } + + throw "don't know how to massage : " + type; + +} + + +DBCollection.prototype._validateObject = function( o ){ + if ( o._ensureSpecial && o._checkModify ) + throw "can't save a DBQuery object"; +} + +DBCollection._allowedFields = { $id : 1 , $ref : 1 , $db : 1 , $MinKey : 1, $MaxKey : 1 }; + +DBCollection.prototype._validateForStorage = function( o ){ + this._validateObject( o ); + for ( var k in o ){ + if ( k.indexOf( "." ) >= 0 ) { + throw "can't have . in field names [" + k + "]" ; + } + + if ( k.indexOf( "$" ) == 0 && ! DBCollection._allowedFields[k] ) { + throw "field names cannot start with $ [" + k + "]"; + } + + if ( o[k] !== null && typeof( o[k] ) === "object" ) { + this._validateForStorage( o[k] ); + } + } +}; + + +DBCollection.prototype.find = function( query , fields , limit , skip, batchSize, options ){ + return new DBQuery( this._mongo , this._db , this , + this._fullName , this._massageObject( query ) , fields , limit , skip , batchSize , options || this.getQueryOptions() ); +} + +DBCollection.prototype.findOne = function( query , fields, options ){ + var cursor = this._mongo.find( this._fullName , this._massageObject( query ) || {} , fields , + -1 /* limit */ , 0 /* skip*/, 0 /* batchSize */ , options || this.getQueryOptions() /* options */ ); + if ( ! cursor.hasNext() ) + return null; + var ret = cursor.next(); + if ( cursor.hasNext() ) throw "findOne has more than 1 result!"; + if ( ret.$err ) + throw "error " + tojson( ret ); + return ret; +} + +DBCollection.prototype.insert = function( obj , _allow_dot ){ + if ( ! obj ) + throw "no object passed to insert!"; + if ( ! _allow_dot ) { + this._validateForStorage( obj ); + } + if ( typeof( obj._id ) == "undefined" && ! Array.isArray( obj ) ){ + var tmp = obj; // don't want to modify input + obj = {_id: new ObjectId()}; + for (var key in tmp){ + obj[key] = tmp[key]; + } + } + this._db._initExtraInfo(); + this._mongo.insert( this._fullName , obj ); + this._lastID = obj._id; + this._db._getExtraInfo("Inserted"); +} + +DBCollection.prototype.remove = function( t , justOne ){ + for ( var k in t ){ + if ( k == "_id" && typeof( t[k] ) == "undefined" ){ + throw "can't have _id set to undefined in a remove expression" + } + } + this._db._initExtraInfo(); + this._mongo.remove( this._fullName , this._massageObject( t ) , justOne ? true : false ); + this._db._getExtraInfo("Removed"); +} + +DBCollection.prototype.update = function( query , obj , upsert , multi ){ + assert( query , "need a query" ); + assert( obj , "need an object" ); + + var firstKey = null; + for (var k in obj) { firstKey = k; break; } + + if (firstKey != null && firstKey[0] == '$') { + // for mods we only validate partially, for example keys may have dots + this._validateObject( obj ); + } else { + // we're basically inserting a brand new object, do full validation + this._validateForStorage( obj ); + } + + // can pass options via object for improved readability + if ( typeof(upsert) === 'object' ) { + assert( multi === undefined, "Fourth argument must be empty when specifying upsert and multi with an object." ); + + opts = upsert; + multi = opts.multi; + upsert = opts.upsert; + } + + this._db._initExtraInfo(); + this._mongo.update( this._fullName , query , obj , upsert ? true : false , multi ? true : false ); + this._db._getExtraInfo("Updated"); +} + +DBCollection.prototype.save = function( obj ){ + if ( obj == null || typeof( obj ) == "undefined" ) + throw "can't save a null"; + + if ( typeof( obj ) == "number" || typeof( obj) == "string" ) + throw "can't save a number or string" + + if ( typeof( obj._id ) == "undefined" ){ + obj._id = new ObjectId(); + return this.insert( obj ); + } + else { + return this.update( { _id : obj._id } , obj , true ); + } +} + +DBCollection.prototype._genIndexName = function( keys ){ + var name = ""; + for ( var k in keys ){ + var v = keys[k]; + if ( typeof v == "function" ) + continue; + + if ( name.length > 0 ) + name += "_"; + name += k + "_"; + + name += v; + } + return name; +} + +DBCollection.prototype._indexSpec = function( keys, options ) { + var ret = { ns : this._fullName , key : keys , name : this._genIndexName( keys ) }; + + if ( ! options ){ + } + else if ( typeof ( options ) == "string" ) + ret.name = options; + else if ( typeof ( options ) == "boolean" ) + ret.unique = true; + else if ( typeof ( options ) == "object" ){ + if ( options.length ){ + var nb = 0; + for ( var i=0; i<options.length; i++ ){ + if ( typeof ( options[i] ) == "string" ) + ret.name = options[i]; + else if ( typeof( options[i] ) == "boolean" ){ + if ( options[i] ){ + if ( nb == 0 ) + ret.unique = true; + if ( nb == 1 ) + ret.dropDups = true; + } + nb++; + } + } + } + else { + Object.extend( ret , options ); + } + } + else { + throw "can't handle: " + typeof( options ); + } + /* + return ret; + + var name; + var nTrue = 0; + + if ( ! isObject( options ) ) { + options = [ options ]; + } + + if ( options.length ){ + for( var i = 0; i < options.length; ++i ) { + var o = options[ i ]; + if ( isString( o ) ) { + ret.name = o; + } else if ( typeof( o ) == "boolean" ) { + if ( o ) { + ++nTrue; + } + } + } + if ( nTrue > 0 ) { + ret.unique = true; + } + if ( nTrue > 1 ) { + ret.dropDups = true; + } + } +*/ + return ret; +} + +DBCollection.prototype.createIndex = function( keys , options ){ + var o = this._indexSpec( keys, options ); + this._db.getCollection( "system.indexes" ).insert( o , true ); +} + +DBCollection.prototype.ensureIndex = function( keys , options ){ + var name = this._indexSpec( keys, options ).name; + this._indexCache = this._indexCache || {}; + if ( this._indexCache[ name ] ){ + return; + } + + this.createIndex( keys , options ); + if ( this.getDB().getLastError() == "" ) { + this._indexCache[name] = true; + } +} + +DBCollection.prototype.resetIndexCache = function(){ + this._indexCache = {}; +} + +DBCollection.prototype.reIndex = function() { + return this._db.runCommand({ reIndex: this.getName() }); +} + +DBCollection.prototype.dropIndexes = function(){ + this.resetIndexCache(); + + var res = this._db.runCommand( { deleteIndexes: this.getName(), index: "*" } ); + assert( res , "no result from dropIndex result" ); + if ( res.ok ) + return res; + + if ( res.errmsg.match( /not found/ ) ) + return res; + + throw "error dropping indexes : " + tojson( res ); +} + + +DBCollection.prototype.drop = function(){ + if ( arguments.length > 0 ) + throw "drop takes no argument"; + this.resetIndexCache(); + var ret = this._db.runCommand( { drop: this.getName() } ); + if ( ! ret.ok ){ + if ( ret.errmsg == "ns not found" ) + return false; + throw "drop failed: " + tojson( ret ); + } + return true; +} + +DBCollection.prototype.findAndModify = function(args){ + var cmd = { findandmodify: this.getName() }; + for (var key in args){ + cmd[key] = args[key]; + } + + var ret = this._db.runCommand( cmd ); + if ( ! ret.ok ){ + if (ret.errmsg == "No matching object found"){ + return null; + } + throw "findAndModifyFailed failed: " + tojson( ret ); + } + return ret.value; +} + +DBCollection.prototype.renameCollection = function( newName , dropTarget ){ + return this._db._adminCommand( { renameCollection : this._fullName , + to : this._db._name + "." + newName , + dropTarget : dropTarget } ) +} + +DBCollection.prototype.validate = function(full) { + var cmd = { validate: this.getName() }; + + if (typeof(full) == 'object') // support arbitrary options here + Object.extend(cmd, full); + else + cmd.full = full; + + var res = this._db.runCommand( cmd ); + + if (typeof(res.valid) == 'undefined') { + // old-style format just put everything in a string. Now using proper fields + + res.valid = false; + + var raw = res.result || res.raw; + + if ( raw ){ + var str = "-" + tojson( raw ); + res.valid = ! ( str.match( /exception/ ) || str.match( /corrupt/ ) ); + + var p = /lastExtentSize:(\d+)/; + var r = p.exec( str ); + if ( r ){ + res.lastExtentSize = Number( r[1] ); + } + } + } + + return res; +} + +DBCollection.prototype.getShardVersion = function(){ + return this._db._adminCommand( { getShardVersion : this._fullName } ); +} + +DBCollection.prototype.getIndexes = function(){ + return this.getDB().getCollection( "system.indexes" ).find( { ns : this.getFullName() } ).toArray(); +} + +DBCollection.prototype.getIndices = DBCollection.prototype.getIndexes; +DBCollection.prototype.getIndexSpecs = DBCollection.prototype.getIndexes; + +DBCollection.prototype.getIndexKeys = function(){ + return this.getIndexes().map( + function(i){ + return i.key; + } + ); +} + + +DBCollection.prototype.count = function( x ){ + return this.find( x ).count(); +} + +/** + * Drop free lists. Normally not used. + * Note this only does the collection itself, not the namespaces of its indexes (see cleanAll). + */ +DBCollection.prototype.clean = function() { + return this._dbCommand( { clean: this.getName() } ); +} + + + +/** + * <p>Drop a specified index.</p> + * + * <p> + * Name is the name of the index in the system.indexes name field. (Run db.system.indexes.find() to + * see example data.) + * </p> + * + * <p>Note : alpha: space is not reclaimed </p> + * @param {String} name of index to delete. + * @return A result object. result.ok will be true if successful. + */ +DBCollection.prototype.dropIndex = function(index) { + assert(index , "need to specify index to dropIndex" ); + + if ( ! isString( index ) && isObject( index ) ) + index = this._genIndexName( index ); + + var res = this._dbCommand( "deleteIndexes" ,{ index: index } ); + this.resetIndexCache(); + return res; +} + +DBCollection.prototype.copyTo = function( newName ){ + return this.getDB().eval( + function( collName , newName ){ + var from = db[collName]; + var to = db[newName]; + to.ensureIndex( { _id : 1 } ); + var count = 0; + + var cursor = from.find(); + while ( cursor.hasNext() ){ + var o = cursor.next(); + count++; + to.save( o ); + } + + return count; + } , this.getName() , newName + ); +} + +DBCollection.prototype.getCollection = function( subName ){ + return this._db.getCollection( this._shortName + "." + subName ); +} + +DBCollection.prototype.stats = function( scale ){ + return this._db.runCommand( { collstats : this._shortName , scale : scale } ); +} + +DBCollection.prototype.dataSize = function(){ + return this.stats().size; +} + +DBCollection.prototype.storageSize = function(){ + return this.stats().storageSize; +} + +DBCollection.prototype.totalIndexSize = function( verbose ){ + var stats = this.stats(); + if (verbose){ + for (var ns in stats.indexSizes){ + print( ns + "\t" + stats.indexSizes[ns] ); + } + } + return stats.totalIndexSize; +} + + +DBCollection.prototype.totalSize = function(){ + var total = this.storageSize(); + var mydb = this._db; + var shortName = this._shortName; + this.getIndexes().forEach( + function( spec ){ + var coll = mydb.getCollection( shortName + ".$" + spec.name ); + var mysize = coll.storageSize(); + //print( coll + "\t" + mysize + "\t" + tojson( coll.validate() ) ); + total += coll.dataSize(); + } + ); + return total; +} + + +DBCollection.prototype.convertToCapped = function( bytes ){ + if ( ! bytes ) + throw "have to specify # of bytes"; + return this._dbCommand( { convertToCapped : this._shortName , size : bytes } ) +} + +DBCollection.prototype.exists = function(){ + return this._db.system.namespaces.findOne( { name : this._fullName } ); +} + +DBCollection.prototype.isCapped = function(){ + var e = this.exists(); + return ( e && e.options && e.options.capped ) ? true : false; +} + +DBCollection.prototype._distinct = function( keyString , query ){ + return this._dbCommand( { distinct : this._shortName , key : keyString , query : query || {} } ); + if ( ! res.ok ) + throw "distinct failed: " + tojson( res ); + return res.values; +} + +DBCollection.prototype.distinct = function( keyString , query ){ + var res = this._distinct( keyString , query ); + if ( ! res.ok ) + throw "distinct failed: " + tojson( res ); + return res.values; +} + + +DBCollection.prototype.aggregate = function( ops ) { + + var arr = ops; + + if ( ! ops.length ) { + arr = []; + for ( var i=0; i<arguments.length; i++ ) { + arr.push( arguments[i] ) + } + } + + return this.runCommand( "aggregate" , { pipeline : arr } ); +} + +DBCollection.prototype.group = function( params ){ + params.ns = this._shortName; + return this._db.group( params ); +} + +DBCollection.prototype.groupcmd = function( params ){ + params.ns = this._shortName; + return this._db.groupcmd( params ); +} + +MapReduceResult = function( db , o ){ + Object.extend( this , o ); + this._o = o; + this._keys = Object.keySet( o ); + this._db = db; + if ( this.result != null ) { + this._coll = this._db.getCollection( this.result ); + } +} + +MapReduceResult.prototype._simpleKeys = function(){ + return this._o; +} + +MapReduceResult.prototype.find = function(){ + if ( this.results ) + return this.results; + return DBCollection.prototype.find.apply( this._coll , arguments ); +} + +MapReduceResult.prototype.drop = function(){ + if ( this._coll ) { + return this._coll.drop(); + } +} + +/** +* just for debugging really +*/ +MapReduceResult.prototype.convertToSingleObject = function(){ + var z = {}; + var it = this.results != null ? this.results : this._coll.find(); + it.forEach( function(a){ z[a._id] = a.value; } ); + return z; +} + +DBCollection.prototype.convertToSingleObject = function(valueField){ + var z = {}; + this.find().forEach( function(a){ z[a._id] = a[valueField]; } ); + return z; +} + +/** +* @param optional object of optional fields; +*/ +DBCollection.prototype.mapReduce = function( map , reduce , optionsOrOutString ){ + var c = { mapreduce : this._shortName , map : map , reduce : reduce }; + assert( optionsOrOutString , "need to supply an optionsOrOutString" ) + + if ( typeof( optionsOrOutString ) == "string" ) + c["out"] = optionsOrOutString; + else + Object.extend( c , optionsOrOutString ); + + var raw = this._db.runCommand( c ); + if ( ! raw.ok ){ + __mrerror__ = raw; + throw "map reduce failed:" + tojson(raw); + } + return new MapReduceResult( this._db , raw ); + +} + +DBCollection.prototype.toString = function(){ + return this.getFullName(); +} + +DBCollection.prototype.toString = function(){ + return this.getFullName(); +} + + +DBCollection.prototype.tojson = DBCollection.prototype.toString; + +DBCollection.prototype.shellPrint = DBCollection.prototype.toString; + +DBCollection.autocomplete = function(obj){ + var colls = DB.autocomplete(obj.getDB()); + var ret = []; + for (var i=0; i<colls.length; i++){ + var c = colls[i]; + if (c.length <= obj.getName().length) continue; + if (c.slice(0,obj.getName().length+1) != obj.getName()+'.') continue; + + ret.push(c.slice(obj.getName().length+1)); + } + return ret; +} + + +// Sharding additions + +/* +Usage : + +mongo <mongos> +> load('path-to-file/shardingAdditions.js') +Loading custom sharding extensions... +true + +> var collection = db.getMongo().getCollection("foo.bar") +> collection.getShardDistribution() // prints statistics related to the collection's data distribution + +> collection.getSplitKeysForChunks() // generates split points for all chunks in the collection, based on the + // default maxChunkSize or alternately a specified chunk size +> collection.getSplitKeysForChunks( 10 ) // Mb + +> var splitter = collection.getSplitKeysForChunks() // by default, the chunks are not split, the keys are just + // found. A splitter function is returned which will actually + // do the splits. + +> splitter() // ! Actually executes the splits on the cluster ! + +*/ + +DBCollection.prototype.getShardDistribution = function(){ + + var stats = this.stats() + + if( ! stats.sharded ){ + print( "Collection " + this + " is not sharded." ) + return + } + + var config = this.getMongo().getDB("config") + + var numChunks = 0 + + for( var shard in stats.shards ){ + + var shardDoc = config.shards.findOne({ _id : shard }) + + print( "\nShard " + shard + " at " + shardDoc.host ) + + var shardStats = stats.shards[ shard ] + + var chunks = config.chunks.find({ _id : sh._collRE( this ), shard : shard }).toArray() + + numChunks += chunks.length + + var estChunkData = shardStats.size / chunks.length + var estChunkCount = Math.floor( shardStats.count / chunks.length ) + + print( " data : " + sh._dataFormat( shardStats.size ) + + " docs : " + shardStats.count + + " chunks : " + chunks.length ) + print( " estimated data per chunk : " + sh._dataFormat( estChunkData ) ) + print( " estimated docs per chunk : " + estChunkCount ) + + } + + print( "\nTotals" ) + print( " data : " + sh._dataFormat( stats.size ) + + " docs : " + stats.count + + " chunks : " + numChunks ) + for( var shard in stats.shards ){ + + var shardStats = stats.shards[ shard ] + + var estDataPercent = Math.floor( shardStats.size / stats.size * 10000 ) / 100 + var estDocPercent = Math.floor( shardStats.count / stats.count * 10000 ) / 100 + + print( " Shard " + shard + " contains " + estDataPercent + "% data, " + estDocPercent + "% docs in cluster, " + + "avg obj size on shard : " + sh._dataFormat( stats.shards[ shard ].avgObjSize ) ) + } + + print( "\n" ) + +} + + +DBCollection.prototype.getSplitKeysForChunks = function( chunkSize ){ + + var stats = this.stats() + + if( ! stats.sharded ){ + print( "Collection " + this + " is not sharded." ) + return + } + + var config = this.getMongo().getDB("config") + + if( ! chunkSize ){ + chunkSize = config.settings.findOne({ _id : "chunksize" }).value + print( "Chunk size not set, using default of " + chunkSize + "Mb" ) + } + else{ + print( "Using chunk size of " + chunkSize + "Mb" ) + } + + var shardDocs = config.shards.find().toArray() + + var allSplitPoints = {} + var numSplits = 0 + + for( var i = 0; i < shardDocs.length; i++ ){ + + var shardDoc = shardDocs[i] + var shard = shardDoc._id + var host = shardDoc.host + var sconn = new Mongo( host ) + + var chunks = config.chunks.find({ _id : sh._collRE( this ), shard : shard }).toArray() + + print( "\nGetting split points for chunks on shard " + shard + " at " + host ) + + var splitPoints = [] + + for( var j = 0; j < chunks.length; j++ ){ + var chunk = chunks[j] + var result = sconn.getDB("admin").runCommand({ splitVector : this + "", min : chunk.min, max : chunk.max, maxChunkSize : chunkSize }) + if( ! result.ok ){ + print( " Had trouble getting split keys for chunk " + sh._pchunk( chunk ) + " :\n" ) + printjson( result ) + } + else{ + splitPoints = splitPoints.concat( result.splitKeys ) + + if( result.splitKeys.length > 0 ) + print( " Added " + result.splitKeys.length + " split points for chunk " + sh._pchunk( chunk ) ) + } + } + + print( "Total splits for shard " + shard + " : " + splitPoints.length ) + + numSplits += splitPoints.length + allSplitPoints[ shard ] = splitPoints + + } + + // Get most recent migration + var migration = config.changelog.find({ what : /^move.*/ }).sort({ time : -1 }).limit( 1 ).toArray() + if( migration.length == 0 ) + print( "\nNo migrations found in changelog." ) + else { + migration = migration[0] + print( "\nMost recent migration activity was on " + migration.ns + " at " + migration.time ) + } + + var admin = this.getMongo().getDB("admin") + var coll = this + var splitFunction = function(){ + + // Turn off the balancer, just to be safe + print( "Turning off balancer..." ) + config.settings.update({ _id : "balancer" }, { $set : { stopped : true } }, true ) + print( "Sleeping for 30s to allow balancers to detect change. To be extra safe, check config.changelog" + + " for recent migrations." ) + sleep( 30000 ) + + for( shard in allSplitPoints ){ + for( var i = 0; i < allSplitPoints[ shard ].length; i++ ){ + var splitKey = allSplitPoints[ shard ][i] + print( "Splitting at " + tojson( splitKey ) ) + printjson( admin.runCommand({ split : coll + "", middle : splitKey }) ) + } + } + + print( "Turning the balancer back on." ) + config.settings.update({ _id : "balancer" }, { $set : { stopped : false } } ) + sleep( 1 ) + } + + splitFunction.getSplitPoints = function(){ return allSplitPoints; } + + print( "\nGenerated " + numSplits + " split keys, run output function to perform splits.\n" + + " ex : \n" + + " > var splitter = <collection>.getSplitKeysForChunks()\n" + + " > splitter() // Execute splits on cluster !\n" ) + + return splitFunction + +} + +DBCollection.prototype.setSlaveOk = function( value ) { + if( value == undefined ) value = true; + this._slaveOk = value; +} + +DBCollection.prototype.getSlaveOk = function() { + if (this._slaveOk != undefined) return this._slaveOk; + return this._db.getSlaveOk(); +} + +DBCollection.prototype.getQueryOptions = function() { + var options = 0; + if (this.getSlaveOk()) options |= 4; + return options; +} + |
