【问题标题】:Racking my head for days on "TypeError: Cannot read property '_id' of undefined"在“TypeError:无法读取未定义的属性'_id'”上绞尽脑汁好几天
【发布时间】:2016-06-26 00:35:26
【问题描述】:

通过 Adam Bretz 和 Colin Ihrig 撰写的“使用 MEAN 进行全栈 JavaScript 开发”第 8 章中的示例,书中的代码似乎并不完整(可能是故意的)。我花了很多时间调试谷歌搜索和搜索 StackOverflow。该脚本可以一直执行到 insertEmployee,然后退出。我无法弄清楚 insertEmployee 参数(pd、devops、acct)的参数是如何设置的。我陷入了“回调地狱”!

基本上我是使用 Node 来填充 MongoDb

如果我将 insertEmployee 函数设置为使用 pd._id 员工很好,但使用 devops._id 或 acct._id 总是会导致 下面的错误

*TypeError: Cannot read property '_id' of undefined
    at insertEmployees (/Users/Bluemagma/Sites/NodeJS Example Application/database/humanresourcesSchema.js:111:17)
    at /Users/Bluemagma/Sites/NodeJS Example Application/database/humanresourcesSchema.js:199:3
    at /Users/Bluemagma/Sites/NodeJS Example Application/database/humanresourcesSchema.js:62:4
    at Function.<anonymous> (/Users/Bluemagma/Sites/NodeJS Example Application/node_modules/mongoose/lib/model.js:3352:16)
    at /Users/Bluemagma/Sites/NodeJS Example Application/node_modules/mongoose/lib/model.js:1863:18
    at /Users/Bluemagma/Sites/NodeJS Example Application/node_modules/async/lib/async.js:726:13
    at /Users/Bluemagma/Sites/NodeJS Example Application/node_modules/async/lib/async.js:52:16
    at done (/Users/Bluemagma/Sites/NodeJS Example Application/node_modules/async/lib/async.js:246:17)
    at /Users/Bluemagma/Sites/NodeJS Example Application/node_modules/async/lib/async.js:44:16
    at /Users/Bluemagma/Sites/NodeJS Example Application/node_modules/async/lib/async.js:723:17
    at /Users/Bluemagma/Sites/NodeJS Example Application/node_modules/async/lib/async.js:167:37
    at model.callbackWrapper (/Users/Bluemagma/Sites/NodeJS Example Application/node_modules/mongoose/lib/model.js:1841:11)
    at next_ (/Users/Bluemagma/Sites/NodeJS Example Application/node_modules/hooks-fixed/hooks.js:89:34)
    at fnWrapper (/Users/Bluemagma/Sites/NodeJS Example Application/node_modules/hooks-fixed/hooks.js:186:18)
    at /Users/Bluemagma/Sites/NodeJS Example Application/node_modules/mongoose/lib/model.js:3352:16
    at /Users/Bluemagma/Sites/NodeJS Example Application/node_modules/mongoose/lib/model.js:228:5*

这是我的 humanresourcesSchema.js 代码

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var db = mongoose.connection;
var dbUrl = 'mongodb://localhost/humanResources';

var TeamSchema = new Schema({
    name: {
        type: String,
        required: true
    }
});

var Team = mongoose.model('Team', TeamSchema);

var EmployeeSchema = new Schema({
    name: {
        first: {
            type: String,
            required: true
        },
        last: {
            type: String,
            required: true
        }
    },
    team: {
        type: Schema.Types.ObjectId,
        ref: 'Team'
    },
    image: {
        type: String,
        default: 'images/user.png'
    },
    address: {
        lines: {
            type: [String]
        },
        postal: {
            type: String
        }
    }
});

var Employee = mongoose.model('Employee', EmployeeSchema);

db.on('error', function () {
    console.log('there was an error communicating with the damn database');
});

function insertTeams (callback) {
    Team.create([{
        name: 'Product Development'
    }, {
        name: 'Dev Ops'
    }, {
        name: 'Accounting'
    }], function (error, pd, devops, acct) {
        if (error) {
            return callback(error);
        } else {
            console.info('teams sucessfully added sir!');
            callback(null, pd, devops, acct);           
        }
    });
}

function retrieveEmployee (data, callback) {
    Employee.findOne({
        _id: data.employee._id
    }).populate('team').exec(function (error, result) {
        if (error) {
            return callback (error);
        } else {
            console.log('*** Single Employee Result ***');
            console.dir(result);
            callback(null, data);
        }
    });
}

function retrieveEmployees (data, callback) {
    Employee.find({
        'name.first': /J/i
    }, function (error, results) {
        if (error) {
            return callback(error);
        } else {
            console.log('*** Multiple Employees Result ***');
            console.dir(results);
            callback(null, data);
        }
    });
}

function insertEmployees (pd, devops, acct, callback) {
  Employee.create([{
    name: {
      first: 'John',
      last: 'Adams'
    },
    Team: pd._id,
    address: {
      lines: ['2 Lincoln Memorial Cir NW'],
      postal: '20037'
    }
  }, {
    name: {
      first: 'Thomas',
      last: 'Jefferson'
    },
    Team: devops._id,
    address: {
      lines: ['1600 Pennsylvania Avenue', 'White House'],
      postal: '20500'
    }
  }, {
    name: {
      first: 'James',
      last: 'Madison'
    },
    team: acct._id,
    address: {
      lines: ['2 15th St NW', 'PO Box 8675309'],
      postal: '20007'
    }
  }, {
    name: {
      first: 'James',
      last: 'Monroe'
    },
    team: acct._id,
    address: {
      lines: ['1850 West Basin Dr SW', 'Suite 210'],
      postal: '20242'
    }
  }], function (error, johnadams) {
    if (error) {
      return callback(error);
    } else {
      console.info('employees successfully added sir!');
      callback(null, {
        team: pd,
        employee: johnadams
      });
    }
  })
}

function updateEmployee (first, last, data, callback) {
    console.log('*** Changin names ***');
    console.dir(data.employee);

    var employee = data.employee;
    employee.name.first = first;
    employee.name.last = last;

    employee.save(function (error, result) {
        if (error) {
            return callback (error);
        } else {
            console.log('*** Changed name to Andrew Jackson ***');
            console.log(result);
            callback(null, data);
        }
    });
}

function removeTeams () {
    console.info("deleting all previously added teams sir!");
    Team.remove({}, function(error, response) {
        if(error) {
            console.error("tried to delete all teams but " + error);
        }
        console.info("done deleting all teams sir!");
    });
}

function removeEmployees () {
    console.info("deleting all previously added employees sir!");
    Employee.remove({}, function(error, response) {
        if(error) {
            console.error("tried to delete all employees but " + error);
        }
        console.info("done deleting all employees sir!");
    });
}

mongoose.connect(dbUrl, function (err) {
    if (err) {
        return console.log('there was a problem connecting to the database sir!' + err);
    }
    console.log('connected to the database sir!');
    removeTeams();
    removeEmployees();
    insertTeams(function (error, pd, devops, acct) {
        if (error) {
            return console.log(error);
        }
        insertEmployees(pd, devops, acct, function (err, result){

            retrieveEmployee(result, function(err, result) {

                retrieveEmployees(result, function(err, result) {

                    updateEmployee('Andrew', 'Jackson', result, function(err, result) {
                        if (err) {
                        console.error(err);
                    } else {
                        console.info("database activity complete sir!");
                    }

                    db.close();
                    process.exit();
                    });
                });
            });
        });
    });
});

感谢 Node 和 Mongo Geniuses 的帮助!我期待了解有关回调的更多信息

【问题讨论】:

  • 我应该添加第 111 行是“团队:devops._id”,这是我第一次使用 pd 以外的参数。如果我将它们全部设置为 Team: pd._id 那么我没有问题。

标签: javascript node.js mongodb


【解决方案1】:
function insertTeams (callback) {
    Team.create([{
        name: 'Product Development'
    }, {
        name: 'Dev Ops'
    }, {
        name: 'Accounting'
    }], function (error, pd, devops, acct) {
        if (error) {
            return callback(error);
        } else {
            console.info('teams sucessfully added sir!');
            callback(null, pd, devops, acct);           
        }
    });
}

这里的回调在我看来很可疑。您将数组作为单个参数传递给 Team.create(),因此回调将被称为 function(err, results),其中 results 是包含您插入的文档的数组。

因此,当您像callback(null, pd, devops, acct); 这样调用回调时,错误将为空,pd 将是您的结果数组,devops 和 acct 将未定义。

您可以将团队作为单独的参数传递给 Team.create,然后也可以使用多个参数调用回调,或者保持原样并调整回调以处理数组。

Mongoose examples.

或者这里是“折磨我好几天,我只需要删除两个括号”版本(希望如此):

function insertTeams (callback) {
    Team.create({
        name: 'Product Development'
    }, {
        name: 'Dev Ops'
    }, {
        name: 'Accounting'
    }, function (error, pd, devops, acct) {
        if (error) {
            return callback(error);
        } else {
            console.info('teams sucessfully added sir!');
            callback(null, pd, devops, acct);           
        }
    });
}

一些放置得当的console.log() 可以帮助您找出丢失变量的位置。

【讨论】:

  • 谢谢!我一定会尝试一下,感谢您发布指向 mongoose 文档的链接!
  • 我按照您的建议取出了括号,它有效!我对它的工作原理仍然一头雾水,但感谢您帮助调试!
  • 在我链接的文档中,有一个示例(在灰色框中),显示了“传递单个文档”和“传递数组”之间的区别。我想您将能够理解其中的区别。我也可以指出 stackoverflow 接受答案的过程:) stackoverflow.com/help/accepted-answer
【解决方案2】:

我感觉您在 insertTeams 函数中遇到错误。

当它调用带有错误的回调函数 (insertEmployees) 时,如果出现错误,该函数根本不会尝试捕获或处理错误。相反,它调用回调并且仅将错误本身作为参数传递。由于 insertEmployees 没有任何错误处理,因此它不会在开始之前检查是否发生了错误。因此,当它尝试调用 devops 的 _id 属性时,devops 是未定义的,因为在调用函数时它没有定义。所以,JS报错了。

有关更多信息,您可能想尝试在 insertTeams 中记录错误(如果出现)。

编辑:我认为问题仍然是使用回调(错误)调用 insertEmployees。您可以访问错误的 _id 字段,因为存在错误,因此至少会返回未定义。但是,其他参数没有定义,因为它们没有传递给函数,所以一旦你尝试访问它们的 _id 字段,你就会得到一个错误,因为你试图访问一个未定义对象的字段.

【讨论】:

  • 这很有道理,感谢您帮助我!
猜你喜欢
  • 2013-09-03
  • 2022-07-27
  • 2022-09-23
  • 2019-09-13
  • 1970-01-01
  • 2020-11-22
  • 2014-12-24
  • 2020-09-03
  • 1970-01-01
相关资源
最近更新 更多