Mongoose JS relationships Mongoose JS relationships mongoose mongoose

Mongoose JS relationships


I think the mongoose-y way to do this would be with the pre/post middleware. For example, when saving a post you could configure mongoose to automatically keep the user collection in sync like so:

post.js

var User = mongoose.model('User');postSchema.pre('save', function(next) {    // Don't do anything unless this is a new Post being created    // If a Post's author can be changed you would also need to check for that here    if (!this.isNew) {        return next();    }    User.update({_id: this._author}, {        $push: {posts: this._id}    })    .then(function() {        next();    })    .then(null, function(err) {        // Whoops! Something broke. You may want to abort this update.        next(err);    });});

You can also set up a similar postSchema.post('remove', ...) middleware to do cascade deletions.

A few things to note:

1) Calling mongoose.model with just one argument like I am above will load the model instead of defining it. Use this to have models reference each other. If you were to use node module.exports you could get cyclic dependencies.

2) Follow @Rob's advice about ObjectId. Don't change your id to Number unless you have a good reason.


populate() doesn't save anything. It is read-based functionality that searches for the _id you are populating and appends it to the mongoose document that you just queried for. All this does is save you a a second query to find the user. Nothing is actually being saved.

In regards to design, I wouldn't even bother having the posts array on the user since it has the potential to grow infinitely. In a practical application, you will already have either the user or the post in memory at any given time, so you will already have their objectId on hand (as Rob said, don't use Number). If you have the user, you can find their posts:

Post.find({_author: author._id}, callback)

similarly if you have the post, you can find the user:

User.findOne({_id: post._author}, callback)

If you don't have either of them on hand and your application is regularly searching for posts by an author's username, you can add that to the post schema and send it in your save request. This way you can make searching for posts by author easy. Switch the post schema to:

var postSchema = new Schema({    title: String,    content: String,    _author: {        _id: {            type: Schema.ObjectId,            ref: 'User'        },        username: String    }});

and your query would be:

Post.find({"_author.username", username}, callback)

It's perfectly OK to repeat data. Applications typically read more than they write, so putting a bit more effort into writing to save time on reading is worth it.