Using populate with sub-documents that also need populate

100 views
Skip to first unread message

Bill Tricarico

unread,
Aug 31, 2013, 5:19:16 AM8/31/13
to mongoo...@googlegroups.com
Hello,

I have a basic Mongoose populate scenario working.  However, any inserted documents added via populate that have fields in need of another populate call are just showing their ObjectId.   How can I write a recursive code block to handle such a situation?

As as example, say I have a collection of C-style functions, where each function has a return data type, a set of parameters, and possibly some dependent functions.  I have three schemas, one of which is self-referencing (the Function schema).

Example:

// schemas.js

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;

var DataType = new Schema({
     name: {type: String, require: true, trim: true, unique: true}
});

module.exports = DataType;

var FunctionParameter = new Schema({
     dataType: { type: ObjectId, ref: 'DataType' }
    ,position: {type: Number, require: true}
    ,name: {type: String, require: true, trim: true}
    ,value: {type: String, require: true, trim: true}
});

module.exports = FunctionParameter;

var Function = new Schema({
     folderId: { type: Number }
    ,name: {type: String, require: true, trim: true}
    ,dependencies: [{ type: ObjectId, ref: 'Function' }]  // self-referencing array of functions
    ,parameters: [{ type: ObjectId, ref: 'FunctionParameter' }] 
    ,definition: {type:String, require: true, trim: true}
    ,returnDataType: { type: ObjectId, ref: 'DataType' }
});

module.exports = Function;


// models.js

var DataTypeSchema = require('../schemas/dataType');
var DataType = mongoose.model('DataType', DataTypeSchema);
module.exports = DataType;

var FunctionParameterSchema = require('../schemas/functionParameter');
var FunctionParameter = mongoose.model('FunctionParameter', FunctionParameterSchema);
module.exports = FunctionParameter;

var FunctionSchema = require('../schemas/function');
var Function = mongoose.model('Function', FunctionSchema);
module.exports = Function;

// controllers.js

// get all functions by folder id
    app.get('/functionsByFolder/:id',function(req,res){
        var id = parseInt(req.params['id']);
        Function
            .find({folderId: id}, function (err, functions){
                if (err) {
                    res.send(err);
                }
                else {
                    var opts = [
                         { path: 'returnDataType', model: 'DataType' }
                        ,{ path: 'parameters', model: 'FunctionParameter' }
                        ,{ path: 'dependencies', model: 'Function' }
                    ];

                    Function.populate(functions,opts, function(err,data){
                        if (err) {
                            res.send(err);
                        }
                        else {
                            res.send(data);
                        }
                    });
                }
            });
    });

When I hit this REST url, the json array of documents looks something like the following.  The highlighted areas are where the ObjectId should be replaced with another child document:

[
  {
    "folderId": 5,
    "name": "add",
    "definition": "return a+b;",
    "returnDataType": {
      "name": "Number",
      "_id": "5220c19cbaca0d8c1a00000e"
    },
    "_id": "5220c19cbaca0d8c1a00004d",
    "parameters": [
      {
        "dataType": "5220c19cbaca0d8c1a00000e",
        "position": 1,
        "name": "a",
        "value": "0",
        "_id": "5220c19cbaca0d8c1a000040"
      },
      {
        "dataType": "5220c19cbaca0d8c1a00000e",
        "position": 2,
        "name": "b",
        "value": "0",
        "_id": "5220c19cbaca0d8c1a000041"
      }
    ],
    "dependencies": []
  },
  {
    "folderId": 5,
    "name": "subtract",
    "definition": "return a-b;",
    "returnDataType": {
      "name": "Number",
      "_id": "5220c19cbaca0d8c1a00000e"
    },
    "_id": "5220c19cbaca0d8c1a00004e",
    "parameters": [
      {
        "dataType": "5220c19cbaca0d8c1a00000e",
        "position": 1,
        "name": "a",
        "value": "0",
        "_id": "5220c19cbaca0d8c1a000042"
      },
      {
        "dataType": "5220c19cbaca0d8c1a00000e",
        "position": 2,
        "name": "b",
        "value": "0",
        "_id": "5220c19cbaca0d8c1a000043"
      }
    ],
    "dependencies": []
  },
  {
    "folderId": 5,
    "name": "multiply",
    "definition": "return a*b;",
    "returnDataType": {
      "name": "Number"
      "_id": "5220c19cbaca0d8c1a00000e"
    },
    "_id": "5220c19cbaca0d8c1a00004f",
    "parameters": [
      {
        "dataType": "5220c19cbaca0d8c1a00000e",
        "position": 1,
        "name": "a",
        "value": "0"
        "_id": "5220c19cbaca0d8c1a000044"
      },
      {
        "dataType": "5220c19cbaca0d8c1a00000e",
        "position": 2,
        "name": "b",
        "value": "0"
        "_id": "5220c19cbaca0d8c1a000045"
      }
    ],
    "dependencies": []
  },
  {
    "folderId": 5,
    "name": "divide",
    "definition": "return a/b;",
    "returnDataType": {
      "name": "Number",
      "_id": "5220c19cbaca0d8c1a00000e"
    },
    "_id": "5220c19cbaca0d8c1a000050",
    "parameters": [
      {
        "dataType": "5220c19cbaca0d8c1a00000e",
        "position": 1,
        "name": "a",
        "value": "0",
        "_id": "5220c19cbaca0d8c1a000046"
      },
      {
        "dataType": "5220c19cbaca0d8c1a00000e",
        "position": 2,
        "name": "b",
        "value": "0",
        "_id": "5220c19cbaca0d8c1a000047"
      }
    ],
    "dependencies": []
  },
  {
    "folderId": 5,
    "name": "factorial",
    "definition": "if (n <= 1) return n;  return n * factorial(n - 1);",
    "returnDataType": {
      "name": "Number",
      "_id": "5220c19cbaca0d8c1a00000e"
    },
    "_id": "5220c19cbaca0d8c1a000051",
    "parameters": [
      {
        "dataType": "5220c19cbaca0d8c1a00000e",
        "position": 1,
        "name": "n",
        "value": "0",
        "_id": "5220c19cbaca0d8c1a000048"
      }
    ],
    "dependencies": []
  },
  {
    "folderId": 5,
    "name": "combination",
    "definition": "if (n <= 1) return n;  return n * factorial(n - 1);",
    "returnDataType": {
      "name": "Number",
      "_id": "5220c19cbaca0d8c1a00000e"
    },
    "_id": "5220c19cbaca0d8c1a000052",
    "parameters": [
      {
        "dataType": "5220c19cbaca0d8c1a00000e",
        "position": 1,
        "name": "n",
        "value": "0",
        "_id": "5220c19cbaca0d8c1a000049"
      },
      {
        "dataType": "5220c19cbaca0d8c1a00000e",
        "position": 2,
        "name": "r",
        "value": "0"
        "_id": "5220c19cbaca0d8c1a00004a",
        "__v": 0
      }
    ],
    "dependencies": [
      {
        "folderId": 5,
        "name": "factorial",
        "definition": "if (n <= 1) return n;  return n * factorial(n - 1);",
        "returnDataType": "5220c19cbaca0d8c1a00000e",
        "_id": "5220c19cbaca0d8c1a000051",
        "parameters": [
          "5220c19cbaca0d8c1a000048"
        ],
        "dependencies": []
      }
    ]
  },
  {
    "folderId": 5,
    "name": "permutation",
    "definition": "float diff = n - k; float numerator = n; for (int i = n - 1; i > diff; i--) { numerator *= i; } return numerator;",
    "returnDataType": {
      "name": "Number",
      "_id": "5220c19cbaca0d8c1a00000e"
    },
    "_id": "5220c19cbaca0d8c1a000053",
    "parameters": [
      {
        "dataType": "5220c19cbaca0d8c1a00000e",
        "position": 1,
        "name": "n",
        "value": "0",
        "_id": "5220c19cbaca0d8c1a00004b"
      },
      {
        "dataType": "5220c19cbaca0d8c1a00000e",
        "position": 2,
        "name": "k",
        "value": "0",
        "_id": "5220c19cbaca0d8c1a00004c"
      }
    ],
    "dependencies": [
      {
        "folderId": 5,
        "name": "factorial",
        "definition": "if (n <= 1) return n;  return n * factorial(n - 1);",
        "returnDataType": "5220c19cbaca0d8c1a00000e",
        "_id": "5220c19cbaca0d8c1a000051",
        "parameters": [
          "5220c19cbaca0d8c1a000048"
        ],
        "dependencies": []
      }
    ]
  }
]

Any help regarding how to handle this particular situation would be greatly appreciated!

Thanks!






Erwin Poeze

unread,
Sep 3, 2013, 9:26:10 AM9/3/13
to mongoo...@googlegroups.com
Hi Bill,

When looking into a similar problem I found this issue https://github.com/LearnBoost/mongoose/issues/601 which states "The latest Mongoose release does support deep population, but only within one schema."
Reply all
Reply to author
Forward
0 new messages