TypeError: populate(...).exec 不是一个函数

Posted

技术标签:

【中文标题】TypeError: populate(...).exec 不是一个函数【英文标题】:TypeError: populate(...).exec is not a function 【发布时间】:2017-03-29 10:57:42 【问题描述】:

我在很大程度上认为这个错误是由于我调用的对象不包含 .populate 函数,虽然我不知道如何改变它来工作。

首先,这里是完整的错误。

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

我指的具体行是exam[0].modules[u].topics[i].populate("questions").exec(function(err,quests) 另一行我认为这里非常重要的是examBoard.find(name:req.body.examBoardName,function(err,exam) 行,它返回不包含.populate 函数的exam

我认为这主要是由于我缺乏经验,而不是逻辑错误,但我不确定。

这是包含错误的代码部分。

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;
                
            
        
    );
);

这是examBoard 架构。

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);

这里是模式的导入,以防万一这里可能出现问题。

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");

【问题讨论】:

【参考方案1】:

您正在从exam[0].modules[u].topics[i] 调用populate 方法,但实际上保存此方法的模型对象是exam[0],因此您可以在考试中以这样的深层对象层次结构填充问题:

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

但是,请稍等,现在模型将在此考试中的所有模块中填充所有主题中的问题。

在您的情况下,您首先按 moduleName 进行过滤,因此您可以配置 populate 选项,如下所示:

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

exam[0].populate(options)

从docs了解更多关于populate参数的信息。

【讨论】:

在所有模块的所有主题中填充所有问题肯定会起作用,尽管当数据库增长时它的效率会非常低。我想您提到了这一点,但是当您说将其移出 for 循环时,我不确定这将如何阻止它填充所有内容,您能举个例子吗? @JonathanWoollett-light 检查我上面用你的用例编辑的答案。 谢谢你,这是我认为我只需要学习存在的东西。 我似乎遇到了另一个我认为与这个问题密切相关的问题 (***.com/questions/40660099/…),当然不必帮我解决这个问题,因为你已经帮了我很多,但以防万一你有任何想法我认为我应该说。

以上是关于TypeError: populate(...).exec 不是一个函数的主要内容,如果未能解决你的问题,请参考以下文章

TypeError(`无效的架构配置:\`$name\` 不是 ` +

Mongoose .populate 随机

猫鼬'populate()'没有填充

Model.populate() 是不是返回一个承诺?

如何正确使用函数 populate()

Populate() ref 嵌套在对象数组中