为什么我的 Mongoose 一对多关系没有正确关联?

Why are my Mongoose One-To-Many Relationships not associating properly?

有谁知道为什么 "users" 和 "posts" 之间的以下一对多关系(用户可以有多个 post)不起作用?看来我已经正确设置了猫鼬关联,但是当创建新的 post 时,不仅 没有 分配给用户,而且用户本身也没有关联任何 post秒。我不确定我在这里做错了什么。

如果您看到下面的 JSON 对象,它应该有一个 user 值,表示创建 post 的用户。您将在下面的 Post 模型中看到,应该创建一个用户值,但实际上并没有。

我做错了什么?

这是创建新 post

后的 JSON 对象
{
    __v: 0
     _id: "587ee8f5a99b1709b012ce8f"
    createdAt: "2017-01-18T04:03:01.446Z"
    message: "This is my first test post!"
    updatedAt: "2017-01-18T04:03:01.446Z"
}

问题:为什么上面的 JSON 中缺少用户字段,尽管它是在下面的 Post 模型中创建的?

这是我的 Post 型号:

// Setup dependencies:
var mongoose = require('mongoose');

// Setup a schema:
var PostSchema = new mongoose.Schema (
    {
        message: {
            type: String,
            minlength: 2,
            maxlength: 2000,
            required: true,
            trim: true,
        }, // end message field
        user: {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'User'
        },
    },
    {
       timestamps: true,
    }
);

// Instantiate our model and export it:
module.exports = mongoose.model('Post', PostSchema)

这是我的用户模型:

// Setup dependencies:
var mongoose = require('mongoose');

// Setup a schema:
var UserSchema = new mongoose.Schema (
    {
        username: {
            type: String,
            minlength: 2,
            maxlength: 20,
            required: true,
            trim: true,
            unique: true, // username must be unique
            dropDups: true,
            lowercase: true,
            validate: {
                validator: function(username) {
                    var regex = /^[a-z0-9_]+$/i;
                    return regex.test(username);
                },
                message: 'Username may contain only letters, numbers or underscores.',
            },
        }, // end username field
        posts: [{
            type: mongoose.Schema.Types.ObjectId,
            ref: 'Post'
        }],
    },
    {
        timestamps: true,
    });

// Instantiate our model and export it:
module.exports = mongoose.model('User', UserSchema)

这是查询数据库的控制器:

注意:这是提交post表单时运行的方法。

// Grab our Mongoose Models:
var User = require('mongoose').model('User');
var Post = require('mongoose').model('Post');

module.exports = {
    // Creates a new post for logged in user:
    newPost: function(req, res) {
        Post.create(req.body)
            .then(function(newPost) {
                return res.json(newPost);
            })
            .catch(function(err) {
                return res.json(err);
            })

    }
};

有谁知道我的关联是否设置不当,这就是为什么我没有让任何实际的 post 或用户出现在他们各自的领域中的原因?

似乎我的服务器端控制器正在正常启动,因为 post 实际上已创建。但是协会本身并没有联系起来,我不确定我做错了什么。

我在下面添加了一个简单的答案来跟进上面的例子。本质上,@cdbajorin 是正确的,我心不在焉地认为有一些自动化正在进行并且没有适当地遵循正确的 mongoose 命令来实现我想要的结果。

我的问题的解决方法如下:

  1. 在用户模型中,将 UserSchema posts 属性更新为一个空数组,而不是 mongoose.Schema.Types.ObjectID,因为对象 ID 无论如何都不会存储在这里,我误解了它是如何工作的。

代码:

posts: [{
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Post'
}],

相反,应该简单地写成:

posts: [],
  1. Server Controller中的newPost方法应该修改如下(详见内联注释):

    newPost: function(req, res) {
        // creates new post:
        Post.create(req.body)
        .then(function(newPost) {
            // look up current user based on session ID: 
            // note: session setup not shown in this example.
            User.findById(req.session.userID)
                .then(function(user) {
                    // push new post into users.posts array from model setup**:
                    user.posts.push(newPost);
                    user.save();
                    return res.json(newPost);
                })
        })
        .catch(function(err) {
            return res.json(err);
        })
    

这确实解决了生成新的 post,然后将其推入用户的 posts 数组(来自 UsersSchema)的问题。

虽然最初 post 的问题已解决,但有人可能会质疑这是否是数据库管理的最佳用途。将 post 存储在用户内部,如本例所示,随着用户和 post 开始加起来,可能会占用大量 space。

这个 post 最终在数据库中被复制了两次:第一次,作为 posts 集合中的文档本身,第二次,作为 posts 数组中的一个对象UserSchema

更好的解决方案是将 post 作为 posts 集合中的唯一文档,但将会话信息中的用户 ID 添加到其中。然后,如果出于任何原因需要所有用户的 post,则基于用户 ID 对 Posts 集合的查询将 return 分配给该用户 ID 的所有 post。然后,数据库中只存在 post 的一个副本,而不是两个。

** 附加说明:另一种修改现有文档的方法是使用实​​例方法,将实际方法插入到用户模型(模式)文件中,并在需要时调用:

例如,在上面的UserSchema模型中的module.exports行之前插入如下代码,可以在需要的时候方便的调用这个函数:

UserSchema.methods.addPost = function(post) {
    this.posts.push(post);
    this.save();
    return true;
};

要从我们的服务器控制器调用此实例方法,我们可以 re-write 我们的控制器如下:

User.findById(req.session.userID)
    .then(function(user) {
     // call our instance method above:
        user.addPost(newPost);
        return res.json(newPost);
     });

post将通过实例方法进行推送和保存,已内置到实例对象本身。