user3673449
user3673449

Reputation: 357

Mongoose populate array is empty

I have defined a UserSchema and a PostSchema in my model.js. UserSchema has a ref to its own Posts, while PostSchema has a ref to its author.

In my controllers.js methods I'm creating a user and a post instance (bound to the newly created user). I'm now trying to populate the user's posts, but mongoose returns an empty array. However, the other way around works (I'm able to retrieve the user by a Post instance).

models.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const UserSchema = new Schema({
    username: String,
    posts: [{
      type: Schema.Types.ObjectId,
      ref: 'Post'
    }]
  })
const PostSchema = new Schema({
    content: String,
    author: {
      type: Schema.Types.ObjectId,
      ref: 'User'
    }
  })
const Post = mongoose.model('Post', PostSchema, 'posts');
const User = mongoose.model('User', UserSchema, 'users');

module.exports = { Post, User }

controllers.js

require('../model/db'); // DB config
const mongoose = require('mongoose');
const models = require('../model/models');

const getUser = (req, res) => {
        const user = new models.User({
            _id: new mongoose.Types.ObjectId(),
            username: 'JohnDoe'
        });

        user.save(function (err) {
            if (err) return res.json(err);

            const post = new models.Post({
                content: 'New Post',
                author: user.id
            });
        post.save(function (err) {
            if (err) return res.json(err);
            models.User.findOne({
                    username: 'JohnDoe'
                })
                .populate('posts').exec((err, user) => {
                    res.json(user);
                })
        });
    });
}

const getPost = (req, res) => {
        const user = new models.User({
            _id: new mongoose.Types.ObjectId(),
            username: 'JohnDoe'
        });

        user.save(function (err, user) {
                if (err) return res.json(err);

                const post = new models.Post({
                    content: 'NewPost',
                    author: user.id
                });

                post.save(function (err, post) {
                    if (err) return res.json(err);
                    models.Post.findOne({
                            content: 'NewPost'
                        })
                        .populate({
                            path: 'author',
                            model: 'User'
                        }).exec((err, user) => {
                            res.json(user);
                        })
                });

            });
}

getUser's result (posts is empty):

{
    "posts": [],
    "_id": "5b9426a6fd187d3949470f54",
    "username": "JohnDoe",
    "__v": 0
}

getPost result (author is correctly returned)

{
    "_id": "5b94287e99072c3a173419f2",
    "content": "NewPost",
    "author": {
        "posts": [],
        "_id": "5b94287e99072c3a173419f0",
        "username": "JohnDoe",
        "__v": 0
    },
    "__v": 0
}

Upvotes: 1

Views: 1045

Answers (1)

chridam
chridam

Reputation: 103365

You need to push the post id to the posts array in the user model as follows

const getUser = (req, res) => {
    const newUser = new models.User({ username: 'JohnDoe' });

    newUser.save(user => {
        if (err) return res.json(err);

        const newPost = new models.Post({
            content: 'New Post',
            author: user._id
        });

        newPost.save(post => {
            if (err) return res.json(err);

            models.User.findByIdAndUpdate(user._id,
                { '$push': { 'posts': post._id } },
                { 'new': true }
            )
            .populate('posts')
            .exec((err, u) => {
                res.json(u);
            })
        });
    });
}

Using async/await

const getUser = async (req, res) => {
    try {
        const newUser = new models.User({ username: 'JohnDoe' });
        const user = await newUser.save();

        const newPost = new models.Post({
            content: 'New Post',
            author: user._id
        });
        const post = await newPost.save();

        const result = await models.User.findByIdAndUpdate(user._id,
            { '$push': { 'posts': post._id } },
            { 'new': true }
        )
        .populate('posts')
        .exec();

        res.json(result)
    } 
    catch (err) {
        return res.json(err);  
    }
}

Upvotes: 1

Related Questions