简体   繁体   中英

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

Does anyone know why the following one-to-many relationship between "users" and "posts" (users can have many posts) is not working? It appears I have setup my mongoose associations correctly, but when a new post is created, not only is it not assigned a user, but the users themselves are also not associated with any posts. I'm not sure what I might be doing wrong here.

If you see the JSON object below, it should have a user value, denoting the user whom created the post. You'll see in the Post Model below, that a user value should be created, but does not.

What am I doing wrong?

Here's the JSON object after creating a new post

{
    __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"
}

Question : Why is the user field missing from the JSON above despite being created in the Post Model below?

Here's my Post Model:

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

Here's my User Model:

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

Here's the Controller that queries the DB:

Note : This is the method that runs when the post form is submitted.

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

    }
};

Does anyone know if my associations are improperly setup and this is why I'm not getting any actual posts or users to show up in their respective fields?

It seems that my server-side controller is firing properly, as the post is actually created. But the associations themselves are not linking up and I'm not sure what I'm doing wrong.

I'm adding just a simple answer below to follow up with the example above. Essentially, @cdbajorin was correct, I was absently thinking there was some automation going on and was not appropriately following through the proper mongoose commands to achieve my desired results.

The solution to my question is as follows:

  1. In the User Model, update the UserSchema posts attribute to be an empty array, instead of a mongoose.Schema.Types.ObjectID , since an object ID is not stored here anyhow and I misunderstood how this works.

The code:

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

Instead, should be written simply:

posts: [],
  1. The newPost method, in the server Controller, should be modified as follows (see comments inline for clarification):

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

This does solve the issue of the new post being generated, and then pushed into a user's posts array (from the UsersSchema ).

Though the issue from the initial post is solved, one may question if this is the best use of database management. Storing posts inside of a user, as this example does, can take up a lot of space as users and posts start to add up.

This post ends up being duplicated in the database twice: first, as a document itself in the posts collection, and secondly, as an object in the posts array within the UserSchema .

A better solution is to keep the post as a unique document in the posts collection, but add the userID from the session information to it. Then, if all of user's posts are needed for any reason, a query to the Posts collection, based on the userID, would return all posts with that userID assigned to it. Then, only one copy of the post exists in the DB instead of two.

** Additional Note: Another way to modify the existing document would be to use an instance method, where an actual method would be inserted into the User Model (Schema) file, and called when needed:

For example, inserting the following code before the module.exports line in the UserSchema Model above, allows for convenient access this function when needed:

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

To call this instance method from our server Controller, we could re-write our Controller as follows:

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

The post will be pushed and saved by the instance method, which has been built into the instance object itself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM