【问题标题】:Cant get referenced object attributes to console.log()无法将引用的对象属性获取到 console.log()
【发布时间】:2018-01-06 09:51:40
【问题描述】:

我无法从另一个对象中获取要记录的引用数据。

我目前有两个模型...

var mongoose = require("mongoose");

学生:

var gameSchema = new mongoose.Schema(
    {
        name: String,
        courses:   [
            {
                type: mongoose.Schema.Types.ObjectId,
                ref:  "Course"
            }
        ]
    });

module.exports = mongoose.model("Student", gameSchema);

课程:

var mongoose = require("mongoose");

var courseSchema = new mongoose.Schema (
    {
        name: String,
        student: [
            {
                id: 
                {
                    type: mongoose.Schema.Types.ObjectId,
                    ref: "Student"
                },
                name: String
            }
        ]
    }
);

module.exports = mongoose.model("Course", courseSchema);

当我 console.log(foundStudent.courses[0].name) 时,我得到了未定义,我不知道为什么......

app.post("/students/:id", function(req, res){
   Student.findById(req.params.id, function(err, foundStudent){
       if(err){
           console.log(err);
       } else {
          Course.create(req.body.class, function(err, createdCourse){
              if(err){
                  console.log(err);
              } else {

                    createdCourse.student.push(foundStudent);
                    createdCourse.save();

                    foundStudent.courses.push(createdCourse);
                    foundStudent.save();
                    res.redirect("/students/" + req.params.id);
              }
          });
       }
   });
});

这里是展示页面...

<div>
    <h1>Student Profile</h1>
    <h2>Name: <%=student.name%></h2>
    <div>
        <h3>Classes:
            <form action="/students/<%= student._id %>" method="POST">
                <% student.courses.forEach(function(course){ %>
                    <li><p><%= course.name %></p></li>
                <% }); %>
            <a href="/students/<%=student._id%>/courses/new">Add Course</a>
            </form>
        </h3>
    </div>
</div>

【问题讨论】:

  • 您必须使用populate 自动获取引用的对象。
  • 这应该进入 get 路线是吗?
  • 是的,在任何返回 DocumentQuery 对象的 find 方法之后。这意味着回调必须移动到 DocumentQuery 对象的exec 方法,例如:Student.findById(id).populate('courses').exec((err, res) =&gt; ...)
  • 遗憾的是,这仍然只保留 id 而不是我的 Student 对象中的值。 app.get("/students/:id", function(req, res){ Student.findById(req.params.id).populate("courses").exec(function(err, foundStudent){ if(err){ console.log(err); } else { console.log(foundStudent); res.render("students/show", {student: foundStudent}); } }); });
  • 我添加了一个示例作为对您主题的回答。解释如何在 SO 注释中正确使用填充占用了太多字符。

标签: javascript node.js


【解决方案1】:

我添加了一个使用mockgoosemocha 的简单测试套件来展示DocumentQuery.populate 的用法。

学生模式

const schema = mongoose.Schema({
    name: String,
    courses: [{ type: mongoose.SchemaTypes.ObjectId, ref: 'Course' }]
});

module.exports = mongoose.model('Student', schema);

课程架构

const schema = mongoose.Schema({
    name: String,
});

module.exports = mongoose.model('Course', schema);

测试套件

const mongoose = require('mongoose');
const mockgoose = new (require('mockgoose').Mockgoose)(mongoose);

const { assert, expect } = require('chai');

const Student = require('../models/student');
const Course = require('../models/course');

var student = null;

before(done => {
    mockgoose.prepareStorage().then(res => {
        mongoose.connect('mongodb://test/testDB', (err) => {
            if (err) {
                return done(err);
            }

            student = new Student({
                name: 'Shane'
            });

            student.save(err => {
                done(err);
            });
        });
    });
});

describe('population', () => {
    it('should populate referenced collection', done => {
        let course = new Course({
            name: 'Applied Sciences'
        });

        // save mock course
        course.save(err => {
            if (err) {
                return done(err);
            }

            student.courses.push(course._id);

            // push changes
            student.save(err => {
                if (err) {
                    return done(err);
                }

                // you can use any other find method that returns a DocumentQuery object
                Student.findOne({
                    name: 'Shane'
                }).populate('courses').exec((err, res) => {
                    if (err) {
                        return done(err);
                    }

                    expect(res.courses).to.have.lengthOf(1);

                    assert.equal(res.courses[0].name, 'Applied Sciences');

                    done();
                });
            });
        });
    });
});

当使用mocha 运行上述程序时,断言将被传递,并且为学生对象提供一门课程。

另外需要注意的是Schema.create 用于一次推送一批对象。是否应该使用doc.saveSchema.create 值得商榷。 create 方法实际上只接受一个文档数组,但在传递一个对象时有一个回退。它在每个文档对象上调用 save 并在保存所有文档时解析。

【讨论】:

  • 感谢您,不久前我参加了 mocha/chain 的短期课程,遗憾的是由于某种原因从未继续使用它。我还是个初学者。这个问题实际上是完全多余的。在我的表单中,我将“name”设置为 name="course[name]" 但在我的代码中我有 req.body.name.....
  • @CollinDeSoto 我注意到的其他事情是您推送对象 (course) 而不是对学生课程集合的 ID 引用。当您更新其中一门课程时,学生的假定课程不会更新。
  • @CollinDeSoto 这是您将引用类型设置为 (mongoose.Schema.Types.ObjectId) 的内容,并且需要您调用 populate,如上所示。否则不会建立任何关系,因为 mongo 不是关系数据库。在 mongo 中,对于推送什么没有严格的规则。您甚至可以将学生对象的课程类型更改为字符串,它会将学生对象字符串化并将其持久化到您的数据库中。
  • 我看到,在我的 app.get("/students",...) 中,我实际上已经填充了 Student.findById,我可能没有在上面的代码中更新它。
  • @CollinDeSoto 我的意思是您可以将任何文档推送到 mongo 集合中。现在,在您的代码中,student.courses 不包含与持久课程的任何关系。当您更新其中一名学生持有的一门课程时,student.courses 中的该对象将不会得到更新。这是因为您将文档推送到数组中,而不是预期的引用类型 mongoose.Schema.Types.ObjectId。我希望这能澄清我正在解决的问题。以上就是在mongo中使用mongoose做关系型数据库的方法。
猜你喜欢
  • 2021-12-15
  • 1970-01-01
  • 1970-01-01
  • 2014-07-28
  • 2016-11-08
  • 2016-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多