0

I have a typical mongoose schematic collection like this:

/* 0 */
{
    "name" : "CIMA",
    "_id" : ObjectId("563ff96bb61f6b2c0e82f93e"),
    "subjects" : [],
    "__v" : 0
}

/* 1 */
{
    "name" : "TESTDDD",
    "_id" : ObjectId("563ffa1db61f6b2c0e82f940"),
    "subjects" : [],
    "__v" : 0
}

/* 2 */
{
    "name" : "testing new thing",
    "_id" : ObjectId("564cbc605adf343c0dc49e95"),
    "subjects" : [],
    "__v" : 0
}

/* 3 */
{
    "name" : "asdfsdf",
    "_id" : ObjectId("564cc0f45adf343c0dc49e96"),
    "subjects" : [],
    "__v" : 0
}

/* 4 */
{
    "name" : "asdfasdfasdfasdfasdfsd",
    "_id" : ObjectId("564ced6ed68ef5d00d5ad4db"),
    "subjects" : [],
    "__v" : 0
}

/* 5 */
{
    "__v" : 0,
    "_id" : ObjectId("563ff5de8e3ae0ce0d5f65a7"),
    "name" : "TEST EDITED",
    "subjects" : []
}

/* 6 */
{
    "__v" : 0,
    "_id" : ObjectId("563566b572b65918095f1db3"),
    "name" : "TEST COURSE",
    "subjects" : []
}

/* 7 */
{
    "name" : "sub one",
    "_id" : ObjectId("564d017d4e13a8640e6b1738"),
    "subjects" : [],
    "__v" : 0
}

/* 8 */
{
    "__v" : 0,
    "_id" : ObjectId("563febb75a9909ae0d25d025"),
    "name" : "testing course",
    "subjects" : []
}

/* 9 */
{
    "__v" : 0,
    "_id" : ObjectId("563ff95ab61f6b2c0e82f93d"),
    "name" : "324234",
    "subjects" : []
}

/* 10 */
{
    "__v" : 0,
    "_id" : ObjectId("563ff8d2b61f6b2c0e82f93b"),
    "name" : "asdfasfd",
    "subjects" : [ 
        {
            "name" : "some suject",
            "_id" : ObjectId("564d05842582c8fe0eb4362d"),
            "topics" : []
        }
    ]
}

/* 11 */
{
    "__v" : 0,
    "_id" : ObjectId("563ff8fbb61f6b2c0e82f93c"),
    "name" : "asfdasfasfd",
    "subjects" : [ 
        {
            "name" : "asdfasdfasdfasdfasdfsd",
            "_id" : ObjectId("564d05c82582c8fe0eb4362e"),
            "topics" : []
        }
    ]
}

/* 12 */
{
    "__v" : 0,
    "_id" : ObjectId("563ff735b61f6b2c0e82f938"),
    "name" : "test",
    "subjects" : [ 
        {
            "_id" : ObjectId("564d04e32582c8fe0eb4362b"),
            "name" : "test subject",
            "topics" : []
        }, 
        {
            "name" : "test subject edite",
            "_id" : ObjectId("564d46a4adcf28580f631eca"),
            "topics" : []
        }, 
        {
            "_id" : ObjectId("564d46b4adcf28580f631ecb"),
            "name" : "test subject edited",
            "topics" : []
        }, 
        {
            "name" : "test subject edite again",
            "_id" : ObjectId("564d4759d6fe04640f99701a"),
            "topics" : []
        }, 
        {
            "_id" : ObjectId("564d4793ef24f5670f62ba22"),
            "name" : "test subject yet again",
            "topics" : []
        }, 
        {
            "name" : "test subject edited TWO TIMES",
            "_id" : ObjectId("564d4989ef24f5670f62ba23"),
            "topics" : []
        }
    ]
}

Now i need the client to receive this with all the _id replaced with id no matter at what level the document is in the nested structure. So I wrote a transformation recursive function like this:

var _ = require('underscore');

module.exports = {
    toClient: transformCollection
}

function transformCollection(theObject) {
var result = null, object = {};

if(theObject instanceof Array) {
    for(var i = 0; i < theObject.length; i++) {
        theObject[i] = process.nextTick(function () {transformCollection(theObject[prop]);}); // <----Assignment
    }
}
else
{
    for (var prop in theObject) {
        if (prop == '_id') {
            theObject.id = theObject._id; // <----Typo
            delete theObject._id;
            delete theObject.__v;
        }
        else if (theObject[prop] instanceof Array) {
            theObject[prop] = process.nextTick(function () {transformCollection(theObject[prop]);}); // <----Assignment
        }
    }
}
return theObject;
   }

And called as:

  courseModel.find(function(err,courses){
            if(err){
                res.json(error.dbRetrievalError);
            }
            else
            {
                res.json(utils.toClient(courses));
            }
        })

So a couple of questions here:

  1. Is it the right way to achieve this?

  2. If yes, then can anyone point my recursive function in the right direction? I am getting a Maximum call stack size exceeded error.

DaBler
  • 2,695
  • 2
  • 26
  • 46
beNerd
  • 3,314
  • 6
  • 54
  • 92
  • possibly related? (if this fixes the problem, then... the answer to #1 is a definitive **No**) http://stackoverflow.com/questions/14463087/is-it-possible-rename-fields-in-the-outputs-of-a-mongo-query-in-pymongo – Kevin B Nov 19 '15 at 22:01
  • Care to give some pointers with mongoose or why this would create a problem? – beNerd Nov 19 '15 at 22:03
  • the aggregate method also exists within mongoose. If it can be done with mongodb directly, chances are you can do it with mongoose too. – Kevin B Nov 19 '15 at 22:03
  • Here's another way: http://stackoverflow.com/questions/7034848/mongodb-output-id-instead-of-id though i'd avoid that method, i wouldn't want to blanket force all routes to replace _id with id. I'd prefer something more... case by case. – Kevin B Nov 19 '15 at 22:13
  • 1
    Problem with all these is that they do not deal with nested subdocuments. That's where I am stuck! – beNerd Nov 19 '15 at 22:14
  • Why are you doing this? `theObject[prop] = process.nextTick` in particular, the `theObject[prop] =` part. – Kevin B Nov 20 '15 at 22:26
  • to go loop through the subset – beNerd Nov 20 '15 at 23:01
  • Ah, gotcha, yea that won't work. you'll need to pass that into the function somehow, and have the function modify it rather than return something. The return becomes rather useless when using process.nextTick() – Kevin B Nov 20 '15 at 23:05
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/95749/discussion-between-benerd-and-kevin-b). – beNerd Nov 20 '15 at 23:07

1 Answers1

0

It looks like you are missing a couple of assignments from the result of your recursion. There is also a typo in your for-in where you set object.id instead of theObject.id.

Does this work?

function transformCollection(theObject) {
    var result = null, object = {};

    if(theObject instanceof Array) {
        for(var i = 0; i < theObject.length; i++) {
            theObject[i] = transformCollection(theObject[i]); // <----Assignment
        }
    }
    else
    {
        for (var prop in theObject) {
            if (prop == '_id') {
                theObject.id = theObject._id; // <----Typo
                delete theObject._id;
            }
            else if (theObject[prop] instanceof Array) {
                theObject[prop] = transformCollection(theObject[prop]); // <----Assignment
            }
        }
    }
    return theObject;
}
carlevans719
  • 106
  • 5
  • to fix the call stack exceeded, you'd need to push calls to transformCollection to the next tick. `process.nextTick(function () {transformCollection(theObject[prop]);});` – Kevin B Nov 20 '15 at 15:44
  • Combining @KevinB and i get a array with all properties mapped to null. Doesn't work! – beNerd Nov 20 '15 at 22:22