Skip to content

Instantly share code, notes, and snippets.

@jabreul
Forked from ronalstal/carc.js
Created May 20, 2014 20:07
Show Gist options
  • Save jabreul/40cb312a747419be1277 to your computer and use it in GitHub Desktop.
Save jabreul/40cb312a747419be1277 to your computer and use it in GitHub Desktop.

Revisions

  1. @ronalstal ronalstal created this gist Dec 4, 2012.
    169 changes: 169 additions & 0 deletions carc.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,169 @@
    /*
    convertAggregateResultToCollection (alias: carc)
    Author: Ronald Stalder <[email protected]>
    */

    var convertAggregateResultToCollection = function (aggResult, options) {

    // void function to supress output
    var _v = function() {};

    // SET DEFAULT OPTIONS UNLESS SPECIFIED
    // options = {
    //
    // "out" : name of the resulting collection, default: "out"
    //
    // "mode" : "replace" eventually existing "out" or create new one
    // (default, will drop the collection first,
    // then same as "append")
    // "append" to existing collection using insert (see "key")
    // "merge" into existing collection using update-upsert on key
    //
    // "key" : <field> use this field as "_id" for the documents
    // in the "out" collection
    // If the option "removeKey" is true, the <field> will
    // be "renamed" to _id, by default it will be copied
    //
    // "objId" an existing "_id" field in the result will be renamed
    // to the value of the "renameKey" option,
    // or deleted if "removeKey" is true,
    // in order to force the generation of an objectId
    //
    // "_id" Default behavior is to take the "_id" from the result.
    // If it does not exist, an ObecjtId will automatically be
    // generated (this will result in "merge" being an "append")
    //
    // "removeKey" : true or false, default=false. See above
    //
    // "renameKey" : (string) existing "_id" in the result will be renamed to this
    // (see above). Default: "origId"
    //
    // "constFields" : array of {name:"name", value:"value"} pairs - default: empty array
    // In the resuling document, a "name": value field will be
    // inserted for each pair in this array
    //
    // "debug": 0 - (default) quiet
    // 1 - print out some basic information
    // 2 - print out some stuff for debugging
    // 3 - print also the result of the aggregate
    // }

    if ( typeof options == 'undefined' ) var options = {};
    if ( typeof options.out == 'undefined' ) options.out = "out";
    if ( typeof options.mode == 'undefined' ) options.mode = "replace";
    if ( typeof options.key == 'undefined' ) options.key = "_id";
    if ( typeof options.removeKey == 'undefined' ) options.removeKey = false;
    if ( typeof options.renameKey == 'undefined' ) options.renameKey = "origId";
    if ( typeof options.constFields == 'undefined' ) options.constFields = [];
    if ( typeof options.debug == 'undefined' ) options.debug = 0;
    var debug = options.debug;

    if ( debug ) print ( "\n*** convertAggregateResultToCollection (carc) -- start\n" );
    if ( debug > 2 ) printjson( aggResult );
    if ( debug > 1 ) printjson( options );

    // check for valid aggregate result in first parameter
    if ( typeof aggResult.result !== "object" ) {
    print( "ERROR: first parameter must be a valid output of aggregate() !\nexitting function" );
    return false;
    }
    try { _v(aggResult.result[0]) }
    catch(err) {
    print( "ERROR: output of aggregate() is empty\nexitting function" );
    return false;
    }

    // set the output collection
    var out = db.getCollection( options.out );
    if ( debug ) print( 'output collection: "' + out + '" output mode is: "'+options.mode+'"' );
    // drop it if in "replace" mode and switch to "append"
    if ( options.mode === "replace" ) {
    out.drop();
    options.mode = "append";
    if ( debug ) print( 'output collection dropped; switched to "append" mode' );
    }

    var r = aggResult.result;

    // DETERMINE _ID FOR OUT COLLECTION
    // asking for _id but there isn't any: switch to "objId"
    var txt = 'the "_id" of the resulting documents will be ';
    if ( options.key === "_id" && typeof r[0]._id === "undefined" ) {
    if ( debug > 1 ) print( 'no _id in result, using "objectId"' );
    options.key = "objId";
    }

    // as a generated objectId
    if ( options.key === "objId" ) {
    if ( debug ) print( txt+'a generated objectId' );

    // from a field in the result
    } else {
    eval( "var _idField = r[0]."+options.key );
    var _idType = typeof _idField;
    // check that given key field exists
    if ( options.key !== "_id" && _idType === "undefined" ) {
    print( "ERROR: given key field '"+options.key
    +"' does not exist\nexitting function" );
    return false;
    }
    if ( debug ) {
    if ( _idType === "object" ) {
    print( txt+"the compound:");
    printjson( _idField );
    } else {
    print( txt+"the key: "+_idField );
    }
    }
    }

    // LOOP THE RESULTS AND CREATE THE DOCUMENTS
    if ( debug ) print( 'processing ' + r.length + ' result records' );
    for ( var i in aggResult.result ) {

    doc = aggResult.result[i];

    // set _id
    if ( !(options.key === "_id" || options.key === "objId") ) {
    // copy the key <field> to _id
    eval( "_idField = doc."+options.key );
    doc._id = _idField;
    // and eventually remove it
    if ( options.removeKey ) delete _idField;
    // if we want objectId and there is an existing _id
    } else if ( options.key === "objId"
    && typeof doc._id !== 'undefined' ) {
    // rename the _id, unless the removeKey option is set to true
    if ( !options.removeKey ) eval( "doc."+options.renameKey+" = doc._id" );
    // delete the _id, so an objectId will be generated
    delete doc._id;
    }

    // add constant Fields
    for ( var j in options.constFields ) {
    eval( "doc."+options.constFields[j].name+"='"+options.constFields[j].value+"'" );
    }

    // insert or update-upsert
    if ( options.mode === "append" ) {
    out.insert( doc );
    } else {
    // prepare update command for the "merge"
    var updCmd = 'out.update({"_id":doc._id},{$set:{';
    // update set all field from the result
    for ( var key in doc ) {
    if ( key == "_id" ) continue;
    updCmd += '"'+key+'": "'+doc[key]+'",'
    }
    updCmd += '}},{"upsert":true})';
    // execute it
    eval( updCmd );
    }
    if ( debug > 1 ) printjson( doc );
    }

    if ( debug ) print ( "\n*** convertAggregateResultToCollection (carc) -- end\n" );
    }

    // set the alias
    var carc = convertAggregateResultToCollection;