4

I largely believe this error is due to the object I'm calling not containing the .populate function, although I have no idea how to change this to work.

To start with, here is the error in full.

TypeError: exam[0].modules[u].topics[i].populate(...).exec is not a function
    at /home/ubuntu/workspace/tests/app.js:425:84
    at Query.Model.$wrapCallback (/home/ubuntu/workspace/tests/node_modules/mongoose/lib/model.js:3336:16)
    at /home/ubuntu/workspace/tests/node_modules/mongoose/node_modules/kareem/index.js:259:21
    at /home/ubuntu/workspace/tests/node_modules/mongoose/node_modules/kareem/index.js:127:16
    at nextTickCallbackWith0Args (node.js:420:9)
    at process._tickCallback (node.js:349:13)


Process exited with code: 1

The specific line I'm referring to is exam[0].modules[u].topics[i].populate("questions").exec(function(err,quests) another line I believe is significantly important here is the line examBoard.find({name:req.body.examBoardName},function(err,exam) which returns exam which does not contain the .populate function.

I presume this is largely down to my lack of experience, and not a logical error, but I'm not sure.

Here is the section of code which contains the error.

app.post("/test",function(req,res)
{
    console.log("\n\n\n\n")
    var time = req.body.time;
    var topicName = [req.body.topic1,req.body.topic2,req.body.topic3,req.body.topic4,req.body.topic5];
    var topicsArray = [];
    examBoard.find({name:req.body.examBoardName},function(err,exam)
    {
        if(err)
        {
            console.log(err);
        }
        else
        {
            for(var u=0;u<exam[0].modules.length;u++)
            {
                console.log("exam[0].modules[u]:\n"+exam[0].modules[u]);
                console.log("req.body.moduleName:\n"+req.body.moduleName);
                if(exam[0].modules[u].name==req.body.moduleName)
                {
                    console.log("topicName[]:\n"+topicName[0]+"\n"+topicName[1]+"\n"+topicName[2]+"\n"+topicName[3]+"\n"+topicName[4]);
                    for(var i=0;i<exam[0].modules[u].topics.length;i++)
                    {
                        console.log("exam[0].modules[u].topics[i].name:\n"+exam[0].modules[u].topics[i].name);
                        for(var t=0;t<topicName.length;t++)
                        {
                            if(exam[0].modules[u].topics[i].name==topicName[t])
                            {
                                // exam[0].modules[u].topics[i].find({name:topicName[t]}).populate("questions").exec(function(err,quests)
                                exam[0].modules[u].topics[i].populate("questions").exec(function(err,quests)
                                {
                                    if(err)
                                    {
                                        console.log(err);
                                    }
                                    else
                                    {
                                        console.log("exam[0].modules[u].topics[i].questions:\n"+exam[0].modules[u].topics[i].questions);
                                        topicsArray.push({
                                            name:topicName[i],
                                            questions:quests
                                        });
                                    }
                                });    
                            } 
                        }
                    }
                    break;
                }
            }
        }
    });
});

Here is the examBoard schema.

var mongoose = require("mongoose");

var topicSchema = new mongoose.Schema({
    name: String,
    questions:[
        {
            type:mongoose.Schema.Types.ObjectId,
            ref:"question"
        }
    ],
});

var moduleSchema = new mongoose.Schema({
    name: String,
    topics: [topicSchema]
});

var examBoardSchema = new mongoose.Schema({
    name: String,
    modules: [moduleSchema]
});

module.exports = mongoose.model("examBoard", examBoardSchema);

And here just in case there may be something wrong here, is the importing of the schema.

var express                 = require("express"),
    mongoose                = require("mongoose"),
    passport                = require("passport"),
    bodyParser              = require("body-parser"),
    LocalStrategy           = require("passport-local"),
    passportLocalMongoose   = require("passport-local-mongoose"),

    seedDB                  = require("./seeds"),
    question                = require("./models/question"),
    examBoard               = require("./models/examBoard"),
    user                    = require("./models/user");
Jonathan Woollett-light
  • 2,813
  • 5
  • 30
  • 58

1 Answers1

1

You are invoking populate method from exam[0].modules[u].topics[i] but actually the model object that hold this method is exam[0] so you can populate questions in your exam in a deep object-hierarchy like this:

exam[0].populate("modules.topics.questions")

But, wait a sec, now the model will populate the questions in all topics in all modules within this exam.

In your case, you filter by moduleName first, so you can configure populate options, so to be like this:

var options = {
    path: 'modules.topics.questions',
    match: { 'modules.name': req.body.moduleName }
};

exam[0].populate(options)

Lear more about populate parameters from docs.

Basim Hennawi
  • 2,651
  • 3
  • 19
  • 31
  • It would certainly work to populate all questions in all topics in all modules, although it will be incredibly inefficient when the database grows. I think you mention this, but when you say to shift it out of the for loop, I'm not sure how this would prevent it populating everything, could you please give an example? – Jonathan Woollett-light Nov 16 '16 at 19:53
  • @JonathanWoollett-light Check my answer above edited with your use-case. – Basim Hennawi Nov 16 '16 at 20:41
  • Thnak you, this is something I think I just needed to learn existed. – Jonathan Woollett-light Nov 16 '16 at 23:24
  • I appear to have come across another problem I thinkis closely related to this one (http://stackoverflow.com/questions/40660099/mongodb-populate-making-empty-array), of course don't feel obliged to help me with this one, as you have already helped me considerably, but just in case you had any idea I thought I should say. – Jonathan Woollett-light Nov 17 '16 at 16:29