mongorc.js 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078
  1. /*
  2. *
  3. * Mongo-Hacker
  4. * MongoDB Shell Enhancements for Hackers
  5. *
  6. * Tyler J. Brock - 2013
  7. *
  8. * http://tylerbrock.github.com/mongo-hacker
  9. *
  10. */
  11. if (_isWindows()) {
  12. print("\nSorry! MongoDB Shell Enhancements for Hackers isn't compatible with Windows.\n");
  13. }
  14. if (typeof db !== 'undefined') {
  15. var current_version = parseFloat(db.serverBuildInfo().version).toFixed(2)
  16. if (current_version < 2.2) {
  17. print("Sorry! MongoDB Shell Enhancements for Hackers is only compatible with Mongo 2.2+\n");
  18. }
  19. }
  20. mongo_hacker_config = {
  21. verbose_shell: true, // additional verbosity
  22. index_paranoia: true, // querytime explain
  23. enhance_api: true, // additonal api extensions
  24. indent: 2, // number of spaces for indent
  25. uuid_type: 'default', // 'java', 'c#', 'python' or 'default'
  26. banner_message: 'Shell Enhanced by MongoHacker Ver. ', //banner message to show on mongo shell load
  27. version: '0.0.3', // current mongo-hacker version
  28. show_banner: true, // show mongo-hacker version banner on startup
  29. // Shell Color Settings
  30. // [<color>, <bold>, <underline>]
  31. colors: {
  32. 'number': [ 'blue', false, false ],
  33. 'null': [ 'red', false, false ],
  34. 'undefined': [ 'magenta', false, false ],
  35. 'objectid': [ 'green', false, false ],
  36. 'string': [ 'green', false, false ],
  37. 'function': [ 'magenta', false, false ],
  38. 'date': [ 'blue', false, false ]
  39. }
  40. }
  41. if (mongo_hacker_config['show_banner']) {
  42. print(mongo_hacker_config['banner_message'] + mongo_hacker_config['version']);
  43. }
  44. function hasDollar(fields){
  45. for (k in fields){
  46. if(k.indexOf('$') !== -1){
  47. return true;
  48. };
  49. };
  50. return false;
  51. }
  52. // Aggregate extension to support alternate API
  53. DBCollection.prototype.aggregate = function( ops ){
  54. if(arguments.length >= 1 && (hasDollar(ops) || hasDollar(ops[0]))){
  55. var arr = ops;
  56. if (!ops.length) {
  57. arr = [];
  58. for (var i=0; i<arguments.length; i++) {
  59. arr.push(arguments[i]);
  60. }
  61. }
  62. var res = this.runCommand("aggregate", {pipeline: arr});
  63. if (!res.ok) {
  64. printStackTrace();
  65. throw "aggregate failed: " + tojson(res);
  66. }
  67. return res;
  68. } else {
  69. return new AggHelper( this ).match( ops || {} );
  70. }
  71. };
  72. // Aggregation Framework Helper
  73. AggHelper = function( collection, fields ){
  74. this.collection = collection;
  75. this.pipeline = [];
  76. };
  77. AggHelper.prototype.execute = function(){
  78. var res = this.collection.runCommand("aggregate", {pipeline: this.pipeline});
  79. if (!res.ok) {
  80. printStackTrace();
  81. throw "aggregate failed: " + tojson(res);
  82. }
  83. return res;
  84. };
  85. AggHelper.prototype.shellPrint = function(){
  86. this.execute().result.forEach(function(result){
  87. printjson(result);
  88. });
  89. };
  90. AggHelper.prototype.project = function( fields ){
  91. if(!fields){
  92. throw "project needs fields";
  93. }
  94. this.pipeline.push({"$project" : fields});
  95. return this;
  96. };
  97. AggHelper.prototype.match = function( criteria ){
  98. if(!criteria){
  99. throw "match needs a query object";
  100. }
  101. this.pipeline.push({"$match" : criteria});
  102. return this;
  103. };
  104. AggHelper.prototype.limit = function( limit ){
  105. if(!limit){
  106. throw "limit needs an integer indicating the max number of documents to limit";
  107. }
  108. this.pipeline.push({"$limit" : limit});
  109. return this;
  110. };
  111. AggHelper.prototype.skip = function( skip ){
  112. if(!skip){
  113. throw "skip needs an integer indicating the number of documents to skip";
  114. }
  115. this.pipeline.push({"$skip" : skip});
  116. return this;
  117. };
  118. AggHelper.prototype.unwind = function( field ){
  119. if(!field){
  120. throw "unwind needs a string indicating the key of an array field to unwind";
  121. }
  122. this.pipeline.push({"$unwind" : "$" + field});
  123. return this;
  124. };
  125. AggHelper.prototype.group = function( group_expression ){
  126. if(!group_expression){
  127. throw "group needs an group expression";
  128. }
  129. this.pipeline.push({"$group" : group_expression});
  130. return this;
  131. };
  132. AggHelper.prototype.sort = function( sort ){
  133. this.pipeline.push({"$sort" : sort});
  134. return this;
  135. };
  136. //----------------------------------------------------------------------------
  137. // API Additions
  138. //----------------------------------------------------------------------------
  139. DBCollection.prototype.filter = function( filter ) {
  140. return new DBQuery(
  141. this._mongo,
  142. this._db,
  143. this,
  144. this._fullName,
  145. this._massageObject( filter )
  146. );
  147. };
  148. DBQuery.prototype.select = function( fields ){
  149. this._fields = fields;
  150. return this;
  151. };
  152. DBQuery.prototype.one = function(){
  153. return this.limit(1)[0];
  154. };
  155. DBQuery.prototype.first = function(field){
  156. var field = field || "$natural";
  157. var sortBy = {};
  158. sortBy[field] = 1;
  159. return this.sort(sortBy).one();
  160. }
  161. DBQuery.prototype.reverse = function( field ){
  162. var field = field || "$natural";
  163. var sortBy = {};
  164. sortBy[field] = -1;
  165. return this.sort(sortBy);
  166. }
  167. DBQuery.prototype.last = function( field ){
  168. var field = field || "$natural";
  169. return this.reverse(field).one();
  170. }
  171. DB.prototype.rename = function(newName) {
  172. if(newName == this.getName() || newName.length === 0)
  173. return;
  174. this.copyDatabase(this.getName(), newName, "localhost");
  175. this.dropDatabase();
  176. db = this.getSiblingDB(newName);
  177. };
  178. //----------------------------------------------------------------------------
  179. // API Modifications (additions and changes)
  180. //----------------------------------------------------------------------------
  181. // Add upsert method which has upsert set as true and multi as false
  182. DBQuery.prototype.upsert = function( upsert ){
  183. assert( upsert , "need an upsert object" );
  184. this._validate(upsert);
  185. this._db._initExtraInfo();
  186. this._mongo.update( this._ns , this._query , upsert , true , false );
  187. this._db._getExtraInfo("Upserted");
  188. };
  189. // Updates are always multi and never an upsert
  190. DBQuery.prototype.update = function( update ){
  191. assert( update , "need an update object" );
  192. this._checkMulti();
  193. this._validate(update);
  194. this._db._initExtraInfo();
  195. this._mongo.update( this._ns , this._query , update , false , true );
  196. this._db._getExtraInfo("Updated");
  197. };
  198. // Replace one document
  199. DBQuery.prototype.replace = function( replacement ){
  200. assert( replacement , "need an update object" );
  201. this._validate(replacement);
  202. this._db._initExtraInfo();
  203. this._mongo.update( this._ns , this._query , replacement , false , false );
  204. this._db._getExtraInfo("Replaced");
  205. };
  206. // Remove is always multi
  207. DBQuery.prototype.remove = function(){
  208. for ( var k in this._query ){
  209. if ( k == "_id" && typeof( this._query[k] ) == "undefined" ){
  210. throw "can't have _id set to undefined in a remove expression";
  211. }
  212. }
  213. this._checkMulti();
  214. this._db._initExtraInfo();
  215. this._mongo.remove( this._ns , this._query , false );
  216. this._db._getExtraInfo("Removed");
  217. };
  218. shellHelper.find = function (query) {
  219. assert(typeof query == "string");
  220. var args = query.split( /\s+/ );
  221. query = args[0];
  222. args = args.splice(1);
  223. if (query !== "") {
  224. var regexp = new RegExp(query, "i");
  225. var result = db.runCommand("listCommands");
  226. for (var command in result.commands) {
  227. var commandObj = result.commands[command];
  228. var help = commandObj.help;
  229. if (commandObj.help.indexOf('\n') != -1 ) {
  230. help = commandObj.help.substring(0, commandObj.help.lastIndexOf('\n'));
  231. }
  232. if (regexp.test(command) || regexp.test(help)) {
  233. var numSpaces = 30 - command.length;
  234. print(colorize(command, 'green'), Array(numSpaces).join(" "), "-", help);
  235. }
  236. }
  237. }
  238. };
  239. //----------------------------------------------------------------------------
  240. // Color Functions
  241. //----------------------------------------------------------------------------
  242. __ansi = {
  243. csi: String.fromCharCode(0x1B) + '[',
  244. reset: '0',
  245. text_prop: 'm',
  246. foreground: '3',
  247. bright: '1',
  248. underline: '4',
  249. colors: {
  250. red: '1',
  251. green: '2',
  252. yellow: '3',
  253. blue: '4',
  254. magenta: '5',
  255. cyan: '6'
  256. }
  257. };
  258. function controlCode( parameters ) {
  259. if ( parameters === undefined ) {
  260. parameters = "";
  261. }
  262. else if (typeof(parameters) == 'object' && (parameters instanceof Array)) {
  263. parameters = parameters.join(';');
  264. }
  265. return __ansi.csi + String(parameters) + String(__ansi.text_prop);
  266. };
  267. function applyColorCode( string, properties ) {
  268. return controlCode(properties) + String(string) + controlCode();
  269. };
  270. function colorize( string, color, bright, underline ) {
  271. var params = [];
  272. var code = __ansi.foreground + __ansi.colors[color];
  273. params.push(code);
  274. if ( bright === true ) params.push(__ansi.bright);
  275. if ( underline === true ) params.push(__ansi.underline);
  276. return applyColorCode( string, params );
  277. };
  278. __indent = Array(mongo_hacker_config.indent + 1).join(' ');
  279. ObjectId.prototype.toString = function() {
  280. return this.str;
  281. };
  282. ObjectId.prototype.tojson = function(indent, nolint) {
  283. return tojson(this);
  284. };
  285. Date.prototype.tojson = function() {
  286. var UTC = Date.printAsUTC ? 'UTC' : '';
  287. var year = this['get'+UTC+'FullYear']().zeroPad(4);
  288. var month = (this['get'+UTC+'Month']() + 1).zeroPad(2);
  289. var date = this['get'+UTC+'Date']().zeroPad(2);
  290. var hour = this['get'+UTC+'Hours']().zeroPad(2);
  291. var minute = this['get'+UTC+'Minutes']().zeroPad(2);
  292. var sec = this['get'+UTC+'Seconds']().zeroPad(2);
  293. if (this['get'+UTC+'Milliseconds']())
  294. sec += '.' + this['get'+UTC+'Milliseconds']().zeroPad(3);
  295. var ofs = 'Z';
  296. if (!Date.printAsUTC) {
  297. var ofsmin = this.getTimezoneOffset();
  298. if (ofsmin !== 0){
  299. ofs = ofsmin > 0 ? '-' : '+'; // This is correct
  300. ofs += (ofsmin/60).zeroPad(2);
  301. ofs += (ofsmin%60).zeroPad(2);
  302. }
  303. }
  304. var isodate = colorize('"' + [year, month, date].join('-') + 'T' + hour +':' + minute + ':' + sec + ofs + '"', "cyan");
  305. return 'ISODate(' + isodate + ')';
  306. };
  307. Array.tojson = function( a , indent , nolint ){
  308. var lineEnding = nolint ? " " : "\n";
  309. if (!indent)
  310. indent = "";
  311. if ( nolint )
  312. indent = "";
  313. if (a.length === 0) {
  314. return "[ ]";
  315. }
  316. var s = "[" + lineEnding;
  317. indent += __indent;
  318. for ( var i=0; i<a.length; i++){
  319. s += indent + tojson( a[i], indent , nolint );
  320. if ( i < a.length - 1 ){
  321. s += "," + lineEnding;
  322. }
  323. }
  324. if ( a.length === 0 ) {
  325. s += indent;
  326. }
  327. indent = indent.substring(__indent.length);
  328. s += lineEnding+indent+"]";
  329. return s;
  330. };
  331. NumberLong.prototype.tojson = function() {
  332. return 'NumberLong(' + colorize('"' + this.toString().match(/-?\d+/)[0] + '"', "red") + ')';
  333. };
  334. NumberInt.prototype.tojson = function() {
  335. return 'NumberInt(' + colorize('"' + this.toString().match(/-?\d+/)[0] + '"', "red") + ')';
  336. };
  337. BinData.prototype.tojson = function(indent , nolint) {
  338. if (this.subtype() === 3) {
  339. return 'UUID(' + colorize('"' + uuidToString(this) + '"', "cyan") + ', ' + colorize('"' + mongo_hacker_config['uuid_type'] + '"', "cyan") + ')'
  340. } else if (this.subtype() === 4) {
  341. return 'UUID(' + colorize('"' + uuidToString(this, "default") + '"', "cyan") + ')'
  342. } else {
  343. return 'BinData(' + colorize(this.subtype(), "red") + ', ' + colorize('"' + this.base64() + '"', "green", true) + ')';
  344. }
  345. };
  346. DBQuery.prototype.shellPrint = function(){
  347. try {
  348. var start = new Date().getTime();
  349. var n = 0;
  350. while ( this.hasNext() && n < DBQuery.shellBatchSize ){
  351. var s = this._prettyShell ? tojson( this.next() ) : tojson( this.next() , "" , true );
  352. print( s );
  353. n++;
  354. }
  355. var output = [];
  356. if (typeof _verboseShell !== 'undefined' && _verboseShell) {
  357. var time = new Date().getTime() - start;
  358. var slowms = getSlowms();
  359. var fetched = "Fetched " + n + " record(s) in ";
  360. if (time > slowms) {
  361. fetched += colorize(time + "ms", "red", true);
  362. } else {
  363. fetched += colorize(time + "ms", "green", true);
  364. }
  365. output.push(fetched);
  366. }
  367. var paranoia = mongo_hacker_config.index_paranoia;
  368. if (typeof paranoia !== 'undefined' && paranoia) {
  369. var explain = this.clone();
  370. explain._ensureSpecial();
  371. explain._query.$explain = true;
  372. explain._limit = Math.abs(n._limit) * -1;
  373. var result = explain.next();
  374. var type = result.cursor;
  375. if (type !== undefined) {
  376. var index_use = "Index[";
  377. if (type == "BasicCursor") {
  378. index_use += colorize( "none", "red", true);
  379. } else {
  380. index_use += colorize( result.cursor.substring(12), "green", true );
  381. }
  382. index_use += "]";
  383. output.push(index_use);
  384. }
  385. }
  386. if ( this.hasNext() ) {
  387. ___it___ = this;
  388. output.push("More[" + colorize("true", "green", true) + "]");
  389. }
  390. print(output.join(" -- "));
  391. }
  392. catch ( e ){
  393. print( e );
  394. }
  395. };
  396. tojsonObject = function( x, indent, nolint ) {
  397. var lineEnding = nolint ? " " : "\n";
  398. var tabSpace = nolint ? "" : __indent;
  399. assert.eq( ( typeof x ) , "object" , "tojsonObject needs object, not [" + ( typeof x ) + "]" );
  400. if (!indent)
  401. indent = "";
  402. if ( typeof( x.tojson ) == "function" && x.tojson != tojson ) {
  403. return x.tojson(indent,nolint);
  404. }
  405. if ( x.constructor && typeof( x.constructor.tojson ) == "function" && x.constructor.tojson != tojson ) {
  406. return x.constructor.tojson( x, indent , nolint );
  407. }
  408. if ( x.toString() == "[object MaxKey]" )
  409. return "{ $maxKey : 1 }";
  410. if ( x.toString() == "[object MinKey]" )
  411. return "{ $minKey : 1 }";
  412. var s = "{" + lineEnding;
  413. // push one level of indent
  414. indent += tabSpace;
  415. var total = 0;
  416. for ( var k in x ) total++;
  417. if ( total === 0 ) {
  418. s += indent + lineEnding;
  419. }
  420. var keys = x;
  421. if ( typeof( x._simpleKeys ) == "function" )
  422. keys = x._simpleKeys();
  423. var num = 1;
  424. for ( var key in keys ){
  425. var val = x[key];
  426. if ( val == DB.prototype || val == DBCollection.prototype )
  427. continue;
  428. s += indent + colorize("\"" + key + "\"", "yellow") + ": " + tojson( val, indent , nolint );
  429. if (num != total) {
  430. s += ",";
  431. num++;
  432. }
  433. s += lineEnding;
  434. }
  435. // pop one level of indent
  436. indent = indent.substring(__indent.length);
  437. return s + indent + "}";
  438. };
  439. tojson = function( x, indent , nolint ) {
  440. if ( x === null )
  441. return colorize("null", "red", true);
  442. if ( x === undefined )
  443. return colorize("undefined", "magenta", true);
  444. if ( x.isObjectId ) {
  445. return 'ObjectId(' + colorize('"' + x.str + '"', "green", false, true) + ')';
  446. }
  447. if (!indent)
  448. indent = "";
  449. var s;
  450. switch ( typeof x ) {
  451. case "string": {
  452. s = "\"";
  453. for ( var i=0; i<x.length; i++ ){
  454. switch (x[i]){
  455. case '"': s += '\\"'; break;
  456. case '\\': s += '\\\\'; break;
  457. case '\b': s += '\\b'; break;
  458. case '\f': s += '\\f'; break;
  459. case '\n': s += '\\n'; break;
  460. case '\r': s += '\\r'; break;
  461. case '\t': s += '\\t'; break;
  462. default: {
  463. var code = x.charCodeAt(i);
  464. if (code < 0x20){
  465. s += (code < 0x10 ? '\\u000' : '\\u00') + code.toString(16);
  466. } else {
  467. s += x[i];
  468. }
  469. }
  470. }
  471. }
  472. s += "\"";
  473. return colorize(s, "green", true);
  474. }
  475. case "number":
  476. return colorize(x, "red");
  477. case "boolean":
  478. return colorize("" + x, "blue");
  479. case "object": {
  480. s = tojsonObject( x, indent , nolint );
  481. if ( ( nolint === null || nolint === true ) && s.length < 80 && ( indent === null || indent.length === 0 ) ){
  482. s = s.replace( /[\s\r\n ]+/gm , " " );
  483. }
  484. return s;
  485. }
  486. case "function":
  487. return colorize(x.toString(), "magenta");
  488. default:
  489. throw "tojson can't handle type " + ( typeof x );
  490. }
  491. };
  492. DBQuery.prototype._validate = function( o ){
  493. var firstKey = null;
  494. for (var k in o) { firstKey = k; break; }
  495. if (firstKey !== null && firstKey[0] == '$') {
  496. // for mods we only validate partially, for example keys may have dots
  497. this._validateObject( o );
  498. } else {
  499. // we're basically inserting a brand new object, do full validation
  500. this._validateForStorage( o );
  501. }
  502. };
  503. DBQuery.prototype._validateObject = function( o ){
  504. if (typeof(o) != "object")
  505. throw "attempted to save a " + typeof(o) + " value. document expected.";
  506. if ( o._ensureSpecial && o._checkModify )
  507. throw "can't save a DBQuery object";
  508. };
  509. DBQuery.prototype._validateForStorage = function( o ){
  510. this._validateObject( o );
  511. for ( var k in o ){
  512. if ( k.indexOf( "." ) >= 0 ) {
  513. throw "can't have . in field names [" + k + "]" ;
  514. }
  515. if ( k.indexOf( "$" ) === 0 && ! DBCollection._allowedFields[k] ) {
  516. throw "field names cannot start with $ [" + k + "]";
  517. }
  518. if ( o[k] !== null && typeof( o[k] ) === "object" ) {
  519. this._validateForStorage( o[k] );
  520. }
  521. }
  522. };
  523. DBQuery.prototype._checkMulti = function(){
  524. if(this._limit > 0 || this._skip > 0){
  525. var ids = this.clone().select({_id: 1}).map(function(o){return o._id;});
  526. this._query['_id'] = {'$in': ids};
  527. return true;
  528. } else {
  529. return false;
  530. }
  531. };
  532. DBQuery.prototype.ugly = function(){
  533. this._prettyShell = false;
  534. return this;
  535. }
  536. function runMatch(cmd, args, regexp) {
  537. clearRawMongoProgramOutput();
  538. if (args) {
  539. run(cmd, args);
  540. } else {
  541. run(cmd);
  542. }
  543. var output = rawMongoProgramOutput();
  544. return output.match(regexp);
  545. };
  546. function getEnv(env_var) {
  547. var env_regex = new RegExp(env_var + '=(.*)');
  548. return runMatch('env', '', env_regex)[1];
  549. };
  550. function getVersion() {
  551. var regexp = /version: (\d).(\d).(\d)/;
  552. return runMatch('mongo', '--version', regexp).slice(1, 4);
  553. };
  554. function isMongos() {
  555. return db.isMaster().msg == 'isdbgrid';
  556. };
  557. function getSlowms(){
  558. if(!isMongos()){
  559. return db.getProfilingStatus().slowms;
  560. } else {
  561. return 100;
  562. }
  563. };
  564. // Override group because map/reduce style is deprecated
  565. DBCollection.prototype.agg_group = function( name, group_field, operation, op_value, filter ) {
  566. var ops = [];
  567. var group_op = { $group: { _id: '$' + group_field } };
  568. if (filter !== undefined) {
  569. ops.push({ '$match': filter });
  570. }
  571. group_op['$group'][name] = { };
  572. group_op['$group'][name]['$' + operation] = op_value;
  573. ops.push(group_op);
  574. return this.aggregate(ops);
  575. };
  576. // Function that groups and counts by group after applying filter
  577. DBCollection.prototype.gcount = function( group_field, filter ) {
  578. return this.agg_group('count', group_field, 'sum', 1, filter);
  579. };
  580. // Function that groups and sums sum_field after applying filter
  581. DBCollection.prototype.gsum = function( group_field, sum_field, filter ) {
  582. return this.agg_group('sum', group_field, 'sum', '$' + sum_field, filter);
  583. };
  584. // Function that groups and averages avg_feld after applying filter
  585. DBCollection.prototype.gavg = function( group_field, avg_field, filter ) {
  586. return this.agg_group('avg', group_field, 'avg', '$' + avg_field, filter);
  587. };
  588. // Improve the default prompt with hostname, process type, and version
  589. prompt = function() {
  590. var serverstatus = db.serverStatus();
  591. var host = serverstatus.host.split('.')[0];
  592. var process = serverstatus.process;
  593. var version = db.serverBuildInfo().version;
  594. var repl_set = db._adminCommand({"replSetGetStatus": 1}).ok !== 0;
  595. var rs_state = '';
  596. if(repl_set) {
  597. members = rs.status().members;
  598. for(var i = 0; i<members.length; i++){
  599. if(members[i].self === true){
  600. rs_state = '[' + members[i].stateStr + ']';
  601. }
  602. };
  603. }
  604. var state = isMongos() ? '[mongos]' : rs_state;
  605. return host + '(' + process + '-' + version + ')' + state + ' ' + db + '> ';
  606. };
  607. // Better show dbs
  608. shellHelper.show = function (what) {
  609. assert(typeof what == "string");
  610. var args = what.split( /\s+/ );
  611. what = args[0]
  612. args = args.splice(1)
  613. if (what == "profile") {
  614. if (db.system.profile.count() == 0) {
  615. print("db.system.profile is empty");
  616. print("Use db.setProfilingLevel(2) will enable profiling");
  617. print("Use db.system.profile.find() to show raw profile entries");
  618. }
  619. else {
  620. print();
  621. db.system.profile.find({ millis: { $gt: 0} }).sort({ $natural: -1 }).limit(5).forEach(
  622. function (x) {
  623. print("" + x.op + "\t" + x.ns + " " + x.millis + "ms " + String(x.ts).substring(0, 24));
  624. var l = "";
  625. for ( var z in x ){
  626. if ( z == "op" || z == "ns" || z == "millis" || z == "ts" )
  627. continue;
  628. var val = x[z];
  629. var mytype = typeof(val);
  630. if ( mytype == "string" ||
  631. mytype == "number" )
  632. l += z + ":" + val + " ";
  633. else if ( mytype == "object" )
  634. l += z + ":" + tojson(val ) + " ";
  635. else if ( mytype == "boolean" )
  636. l += z + " ";
  637. else
  638. l += z + ":" + val + " ";
  639. }
  640. print( l );
  641. print("\n");
  642. }
  643. )
  644. }
  645. return "";
  646. }
  647. if (what == "users") {
  648. db.system.users.find().forEach(printjson);
  649. return "";
  650. }
  651. if (what == "collections" || what == "tables") {
  652. db.getCollectionNames().forEach(function (x) { print(x) });
  653. return "";
  654. }
  655. if (what == "dbs" || what == "databases") {
  656. var dbs = db.getMongo().getDBs();
  657. var dbinfo = [];
  658. var maxNameLength = 0;
  659. var maxGbDigits = 0;
  660. dbs.databases.forEach(function (x){
  661. var sizeStr = (x.sizeOnDisk / 1024 / 1024 / 1024).toFixed(3);
  662. var nameLength = x.name.length;
  663. var gbDigits = sizeStr.indexOf(".");
  664. if( nameLength > maxNameLength) maxNameLength = nameLength;
  665. if( gbDigits > maxGbDigits ) maxGbDigits = gbDigits;
  666. dbinfo.push({
  667. name: x.name,
  668. size: x.sizeOnDisk,
  669. size_str: sizeStr,
  670. name_size: nameLength,
  671. gb_digits: gbDigits
  672. });
  673. });
  674. dbinfo.sort(function (a,b) { a.name - b.name });
  675. dbinfo.forEach(function (db) {
  676. var namePadding = maxNameLength - db.name_size;
  677. var sizePadding = maxGbDigits - db.gb_digits;
  678. var padding = Array(namePadding + sizePadding + 3).join(" ");
  679. if (db.size > 1) {
  680. print(colorize(db.name, "green", true) + padding + db.size_str + "GB");
  681. } else {
  682. print(colorize(db.name, "green", true) + padding + "(empty)");
  683. }
  684. });
  685. return "";
  686. }
  687. if (what == "log" ) {
  688. var n = "global";
  689. if ( args.length > 0 )
  690. n = args[0]
  691. var res = db.adminCommand( { getLog : n } );
  692. if ( ! res.ok ) {
  693. print("Error while trying to show " + n + " log: " + res.errmsg);
  694. return "";
  695. }
  696. for ( var i=0; i<res.log.length; i++){
  697. print( res.log[i] )
  698. }
  699. return ""
  700. }
  701. if (what == "logs" ) {
  702. var res = db.adminCommand( { getLog : "*" } )
  703. if ( ! res.ok ) {
  704. print("Error while trying to show logs: " + res.errmsg);
  705. return "";
  706. }
  707. for ( var i=0; i<res.names.length; i++){
  708. print( res.names[i] )
  709. }
  710. return ""
  711. }
  712. if (what == "startupWarnings" ) {
  713. var dbDeclared, ex;
  714. try {
  715. // !!db essentially casts db to a boolean
  716. // Will throw a reference exception if db hasn't been declared.
  717. dbDeclared = !!db;
  718. } catch (ex) {
  719. dbDeclared = false;
  720. }
  721. if (dbDeclared) {
  722. var res = db.adminCommand( { getLog : "startupWarnings" } );
  723. if ( res.ok ) {
  724. if (res.log.length == 0) {
  725. return "";
  726. }
  727. print( "Server has startup warnings: " );
  728. for ( var i=0; i<res.log.length; i++){
  729. print( res.log[i] )
  730. }
  731. return "";
  732. } else if (res.errmsg == "unauthorized") {
  733. // Don't print of startupWarnings command failed due to auth
  734. return "";
  735. } else {
  736. print("Error while trying to show server startup warnings: " + res.errmsg);
  737. return "";
  738. }
  739. } else {
  740. print("Cannot show startupWarnings, \"db\" is not set");
  741. return "";
  742. }
  743. }
  744. throw "don't know how to show [" + what + "]";
  745. }
  746. printShardingStatus = function( configDB , verbose ){
  747. if (configDB === undefined)
  748. configDB = db.getSisterDB('config')
  749. var version = configDB.getCollection( "version" ).findOne();
  750. if ( version == null ){
  751. print( "printShardingStatus: this db does not have sharding enabled. be sure you are connecting to a mongos from the shell and not to a mongod." );
  752. return;
  753. }
  754. var raw = "";
  755. var output = function(s){
  756. raw += s + "\n";
  757. }
  758. output( "--- Sharding Status --- " );
  759. output( " sharding version: " + tojson( configDB.getCollection( "version" ).findOne(), " " ) );
  760. output( " shards:" );
  761. configDB.shards.find().sort( { _id : 1 } ).forEach(
  762. function(z){
  763. output( " " + tojsononeline( z ) );
  764. }
  765. );
  766. output( " databases:" );
  767. configDB.databases.find().sort( { name : 1 } ).forEach(
  768. function(db){
  769. output( " " + tojsononeline(db,"",true) );
  770. if (db.partitioned){
  771. configDB.collections.find( { _id : new RegExp( "^" +
  772. RegExp.escape(db._id) + "\\." ) } ).
  773. sort( { _id : 1 } ).forEach( function( coll ){
  774. if ( coll.dropped == false ){
  775. output( " " + coll._id );
  776. output( " shard key: " + tojson(coll.key, 0, true) );
  777. output( " chunks:" );
  778. res = configDB.chunks.aggregate(
  779. { "$match": { ns: coll._id } },
  780. { "$group": { _id: "$shard", nChunks: { "$sum": 1 } } }
  781. ).result
  782. var totalChunks = 0;
  783. res.forEach( function(z){
  784. totalChunks += z.nChunks;
  785. output( " " + z._id + ": " + z.nChunks );
  786. } )
  787. if ( totalChunks < 20 || verbose ){
  788. configDB.chunks.find( { "ns" : coll._id } ).sort( { min : 1 } ).forEach(
  789. function(chunk){
  790. output( " " +
  791. tojson( chunk.min, 0, true) + " -> " +
  792. tojson( chunk.max, 0, true ) +
  793. " on: " + colorize(chunk.shard, "cyan") + " " +
  794. ( chunk.jumbo ? "jumbo " : "" )
  795. );
  796. }
  797. );
  798. }
  799. else {
  800. output( "\t\t\ttoo many chunks to print, use verbose if you want to force print" );
  801. }
  802. configDB.tags.find( { ns : coll._id } ).sort( { min : 1 } ).forEach(
  803. function( tag ) {
  804. output( " tag: " + tag.tag + " " + tojson( tag.min ) + " -> " + tojson( tag.max ) );
  805. }
  806. )
  807. }
  808. }
  809. )
  810. }
  811. }
  812. );
  813. print( raw );
  814. }
  815. function listDbs(){
  816. return db.adminCommand("listDatabases").databases.map(function(d){return d.name});
  817. }
  818. this.__proto__.constructor.autocomplete = listDbs;function base64ToHex(base64) {
  819. var base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  820. var hexDigits = "0123456789abcdef";
  821. var hex = "";
  822. for (var i = 0; i < 24; ) {
  823. var e1 = base64Digits.indexOf(base64[i++]);
  824. var e2 = base64Digits.indexOf(base64[i++]);
  825. var e3 = base64Digits.indexOf(base64[i++]);
  826. var e4 = base64Digits.indexOf(base64[i++]);
  827. var c1 = (e1 << 2) | (e2 >> 4);
  828. var c2 = ((e2 & 15) << 4) | (e3 >> 2);
  829. var c3 = ((e3 & 3) << 6) | e4;
  830. hex += hexDigits[c1 >> 4];
  831. hex += hexDigits[c1 & 15];
  832. if (e3 != 64) {
  833. hex += hexDigits[c2 >> 4];
  834. hex += hexDigits[c2 & 15];
  835. }
  836. if (e4 != 64) {
  837. hex += hexDigits[c3 >> 4];
  838. hex += hexDigits[c3 & 15];
  839. }
  840. }
  841. return hex;
  842. }
  843. function hexToBase64(hex) {
  844. var base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  845. var base64 = "";
  846. var group;
  847. for (var i = 0; i < 30; i += 6) {
  848. group = parseInt(hex.substr(i, 6), 16);
  849. base64 += base64Digits[(group >> 18) & 0x3f];
  850. base64 += base64Digits[(group >> 12) & 0x3f];
  851. base64 += base64Digits[(group >> 6) & 0x3f];
  852. base64 += base64Digits[group & 0x3f];
  853. }
  854. group = parseInt(hex.substr(30, 2), 16);
  855. base64 += base64Digits[(group >> 2) & 0x3f];
  856. base64 += base64Digits[(group << 4) & 0x3f];
  857. base64 += "==";
  858. return base64;
  859. }
  860. var platformSpecificUuidModifications = {
  861. "java": function (hex) {
  862. var msb = hex.substr(0, 16);
  863. var lsb = hex.substr(16, 16);
  864. msb = msb.substr(14, 2) + msb.substr(12, 2) + msb.substr(10, 2) + msb.substr(8, 2)
  865. + msb.substr(6, 2) + msb.substr(4, 2) + msb.substr(2, 2) + msb.substr(0, 2);
  866. lsb = lsb.substr(14, 2) + lsb.substr(12, 2) + lsb.substr(10, 2) + lsb.substr(8, 2)
  867. + lsb.substr(6, 2) + lsb.substr(4, 2) + lsb.substr(2, 2) + lsb.substr(0, 2);
  868. return msb + lsb;
  869. },
  870. "c#": function (hex) {
  871. return hex.substr(6, 2) + hex.substr(4, 2) + hex.substr(2, 2) + hex.substr(0, 2)
  872. + hex.substr(10, 2) + hex.substr(8, 2) + hex.substr(14, 2) + hex.substr(12, 2)
  873. + hex.substr(16, 16);
  874. },
  875. "python": function (hex) {
  876. return hex;
  877. },
  878. "default": function (hex) {
  879. return hex;
  880. }
  881. };
  882. function UUID(uuid, type) {
  883. var hex = uuid.replace(/[{}-]/g, "");
  884. var typeNum = 4;
  885. if (type != undefined) {
  886. typeNum = 3;
  887. hex = platformSpecificUuidModifications[type](hex);
  888. }
  889. return new BinData(typeNum, hexToBase64(hex));
  890. }
  891. function uuidToString(uuid, uuidType) {
  892. var uuidType = uuidType || mongo_hacker_config['uuid_type'];
  893. var hex = platformSpecificUuidModifications[uuidType](base64ToHex(uuid.base64()));
  894. return hex.substr(0, 8) + '-' + hex.substr(8, 4) + '-' + hex.substr(12, 4)
  895. + '-' + hex.substr(16, 4) + '-' + hex.substr(20, 12);
  896. }
  897. setVerboseShell(true);
  898. DBQuery.prototype._prettyShell = true
  899. DB.prototype._getExtraInfo = function(action) {
  900. if ( typeof _verboseShell === 'undefined' || !_verboseShell ) {
  901. __callLastError = true;
  902. return;
  903. }
  904. // explicit w:1 so that replset getLastErrorDefaults aren't used here which would be bad.
  905. var startTime = new Date().getTime();
  906. var res = this.getLastErrorCmd(1);
  907. if (res) {
  908. if (res.err !== undefined && res.err !== null) {
  909. // error occurred, display it
  910. print(res.err);
  911. return;
  912. }
  913. var info = action + " ";
  914. // hack for inserted because res.n is 0
  915. info += action != "Inserted" ? res.n : 1;
  916. if (res.n > 0 && res.updatedExisting !== undefined) info += " " + (res.updatedExisting ? "existing" : "new");
  917. info += " record(s) in ";
  918. var time = new Date().getTime() - startTime;
  919. var slowms = getSlowms();
  920. if (time > slowms) {
  921. info += colorize(time + "ms", "red", true);
  922. } else {
  923. info += colorize(time + "ms", "green", true);
  924. }
  925. print(info);
  926. }
  927. };