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

时间:2017-01-18 04:50:22

标签: javascript node.js mongoose one-to-many mean-stack

有谁知道为什么"用户"之间存在以下一对多的关系?和"帖子" (用户可以有很多帖子)不工作?我似乎已正确设置了我的猫鼬关联,但是当创建新帖子时,不仅分配了用户,而且用户本身也与任何帖子。我不确定我在这里做错了什么。

如果您在下面看到JSON对象,则它应该具有user值,表示创建帖子的用户。您将在下面的帖子模型中看到应该创建用户值,但不是。

我做错了什么?

创建新帖子

后,这里是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中缺少用户字段?

这是我的帖子模型:

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

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

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

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

    }
};

是否有人知道我的关联是否设置不正确,这就是为什么我没有在各自的字段中显示任何实际帖子或用户?

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

1 个答案:

答案 0 :(得分:0)

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

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

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

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

    相反,应该简单地写一下:

    posts: [],
    
    1. 服务器控制器中的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);
          })
      
    2. 这确实解决了正在生成的新帖子的问题,然后将其推送到用户的posts数组(来自UsersSchema)。

      虽然初始帖子的问题已经解决,但人们可能会质疑这是否是数据库管理的最佳用途。如此示例所示,在用户内部存储帖子会占用大量空间,因为用户和帖子开始加起来。

      此帖最终会在数据库中重复两次:首先,作为posts集合中的文档本身,其次,作为posts数组中UserSchema数组中的对象。

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

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

      例如,在module.exports模型中的UserSchema行之前插入以下代码,可以在需要时方便地访问此功能:

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

      要从我们的服务器控制器调用此实例方法,我们可以按如下方式重新编写Controller:

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

      将通过实例方法推送和保存帖子,该方法已内置到实例对象本身中。