Permalink
Browse files

Initial commit.

  • Loading branch information...
0 parents commit 0a218993a69f91c39328818088f586e13aa2ec30 @skratchdot committed May 1, 2012
Showing with 184 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +46 −0 README.md
  3. +104 −0 flatten.js
  4. +33 −0 tests/all.js
@@ -0,0 +1 @@
+.project
@@ -0,0 +1,46 @@
+# MongoDB - flatten.js #
+
+[Project Page](http://skratchdot.github.com/mongodb-flatten/)
+[Source Code](https://github.com/skratchdot/mongodb-flatten/)
+[Issues](https://github.com/skratchdot/mongodb-flatten/issues/)
+
+## Description: ##
+
+The flatten() function is a mapReduce that flattens documents into
+key/value pairs. Since this is a mapReduce, you can access the
+keys via 'value.data.k' and the values via 'value.data.v'.
+
+## Usage: ##
+
+ // Flatten all user documents, and return the result inline.
+ result = db.users.flatten();
+
+ // Flatten all user documents, and store the result in the users_flattened collection
+ result = db.users.flatten('users_flattened');
+
+ // Flatten user documents that have the first name of Bob. Store in a collection
+ db.users.flatten({
+ 'out' : 'users_flattened',
+ 'query' : { 'name.first' : 'Bob' }
+ });
+
+ // Get the number of keys in one document
+ db.users.flatten({
+ query : { '_id' : ObjectId('4f9c2374992274fc8d468675') }
+ }).results[0].value.data.length;
+
+## Installation: ##
+
+Download: [flatten.js](https://github.com/skratchdot/mongodb-flatten/raw/master/flatten.js)
+
+### Option 1 ###
+
+Add this script to your .mongorc.js file.
+
+See: http://www.mongodb.org/display/DOCS/Overview+-+The+MongoDB+Interactive+Shell#Overview-TheMongoDBInteractiveShell-.mongorc.js
+
+### Option 2 ###
+
+Start the shell after executing this script
+
+ mongo --shell flatten.js
@@ -0,0 +1,104 @@
+/*global DBCollection: false, emit: false */
+/*jslint devel: false, unparam: true, nomen: true, maxerr: 50, indent: 4 */
+/**
+ * MongoDB - flatten.js
+ *
+ * Version: 1.0
+ * Date: April 29, 2012
+ * Project: http://skratchdot.github.com/mongodb-flatten/
+ * Source Code: https://github.com/skratchdot/mongodb-flatten/
+ * Issues: https://github.com/skratchdot/mongodb-flatten/issues/
+ * Dependencies: MongoDB v1.8+
+ *
+ * Description:
+ *
+ * The flatten() function is a mapReduce that flattens documents into
+ * key/value pairs. Since this is a mapReduce, you can access the
+ * keys via 'value.data.k' and the values via 'value.data.v'.
+ *
+ * Usage:
+ *
+ * // Flatten all user documents, and return the result inline.
+ * result = db.users.flatten();
+ *
+ * // Flatten all user documents, and store the result in the users_flattened collection
+ * result = db.users.flatten('users_flattened');
+ *
+ * // Flatten user documents that have the first name of Bob. Store in a collection
+ * db.users.flatten({
+ * 'out' : 'users_flattened',
+ * 'query' : { 'name.first' : 'Bob' }
+ * });
+ *
+ * // Get the number of keys in one document
+ * db.users.flatten({
+ * query : { '_id' : ObjectId('4f9c2374992274fc8d468675') }
+ * }).results[0].value.data.length;
+ *
+ * Copyright (c) 2012 SKRATCHDOT.COM
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+(function () {
+ 'use strict';
+
+ /**
+ * @function
+ * @name flatten
+ * @memberOf DBCollection
+ * @param {object} optionsOrOutString This function accepts the same options as mapReduce
+ */
+ DBCollection.prototype.flatten = function (optionsOrOutString) {
+ var map, reduce, options = {};
+
+ // Declare our map function
+ // This will emit keyStrings for all the simple values (aka non-object and non-array)
+ map = function () {
+ var emitKeys = function (id, node, keyString) {
+ var key, newKey, type = typeof (node);
+ if (type === 'object' || type === 'array') {
+ for (key in node) {
+ if (node.hasOwnProperty(key)) {
+ newKey = (keyString === '' ? key : keyString + '.' + key);
+ if (newKey === '_id') {
+ emit(id, {k : '_id', v : node[key]});
+ } else {
+ emitKeys(id, node[key], newKey);
+ }
+ }
+ }
+ } else {
+ emit(id, {k : keyString, v : node});
+ }
+ };
+ emitKeys(this._id, this, '');
+ };
+
+ // Declare our reduce function
+ reduce = function (key, values) {
+ return { data : values };
+ };
+
+ // Start to setup our options struct
+ if (typeof optionsOrOutString === 'object') {
+ options = optionsOrOutString;
+ } else if (typeof optionsOrOutString === 'string') {
+ options.out = optionsOrOutString;
+ }
+
+ // The default value for out is 'inline'
+ if (!options.hasOwnProperty('out')) {
+ options.out = { inline : 1 };
+ }
+
+ // Make sure to override certain options
+ options.map = map;
+ options.reduce = reduce;
+ options.mapreduce = this._shortName;
+
+ // Execute and return
+ return this.mapReduce(map, reduce, options);
+ };
+
+}());
@@ -0,0 +1,33 @@
+(function () {
+ var t = db.jstests_all;
+ t.drop();
+
+ t.save( { a : { b : 'foo', c : 'bar' }, d : 42 } );
+
+ // result can't really be queried b/c it's not a real collection
+ r = t.flatten();
+ assert.eq( 1, r.find().length );
+
+ // now we can query since we stored our results in a collection
+ r = t.flatten('jstests_all_results');
+ assert.eq( 1, r.find().count() );
+ // search for keys
+ assert.eq( 1, r.find({'value.data.k':'_id'}).count() );
+ assert.eq( 1, r.find({'value.data.k':'a.b'}).count() );
+ assert.eq( 1, r.find({'value.data.k':'a.c'}).count() );
+ assert.eq( 1, r.find({'value.data.k':'d'}).count() );
+ // these keys shouldn't exist
+ assert.eq( 0, r.find({'value.data.k':'a'}).count() );
+ assert.eq( 0, r.find({'value.data.k':'e'}).count() );
+ assert.eq( 0, r.find({'value.data.k':'e'}).count() );
+ // search for values
+ assert.eq( 1, r.find({'value.data.v':'foo'}).count() );
+ assert.eq( 1, r.find({'value.data.v':'bar'}).count() );
+ assert.eq( 1, r.find({'value.data.v':42}).count() );
+ // these values don't exist
+ assert.eq( 0, r.find({'value.data.k':'foobar'}).count() );
+ assert.eq( 0, r.find({'value.data.k':111}).count() );
+
+ t.drop();
+ db.jstests_all_results.drop();
+}());

0 comments on commit 0a21899

Please sign in to comment.