Search code examples
node.jsmongodbexpressmongoosemongoose-schema

Mongoose do not populate objectid in an objectid of array


THIS PROBLEM IS A LITTLE LONGER. SO I TYPED BOLD THE CRITICAL INFORMATIONS FOR YOU.

I develop a project like stackoverflow. I have 4 databases which are:

  • problems
  • users
  • solutions
  • comments

I referrenced these schemas each other. Here is the Schemas:

Problem Schema

const problemSchema = new mongoose.Schema({
    title: {
        type: String,
        required: [true, 'You have to enter a title']
    },
    content: {
        type: String,
        required: [true, 'You have to enter a content']
    },
    createdAt: {
        type: Date,
        default: Date.now()
    },
    slug: {
        type: String
    },
    solution: [
        {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'Solution'
        },
    ],
    comment: [
        {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'Comment'
        }
    ],
    votes: {
        type: Number,
        default: 0
    },
    views: {
        type: Number,
        default: 0
    },
    user: {
        type: mongoose.Schema.Types.ObjectId,
        required: true,
        ref: 'User'
    }
})

module.exports = mongoose.model('Problem', problemSchema)

User Schema:

const userSchema = new mongoose.Schema({


    name: {
        type: String,
        required: true
    },
    email: {
        type: String,
        required: [true, 'You have to enter an email'],
        unique: true,
        match: [
            /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/,
            'Please provide a valid email address.'
        ]
    },
    password: {
        type: String,
        required: [true, 'You have to enter a password'],
        minlength: [6, 'Your password cannot be less than 6 character.'],
        select: false
    },
    role: {
        type: String,
        default: 'user',
        enum: ['user', 'admin']
    },
    createdAt: {
        type: Date,
        default: Date.now()
    },
    about: {
        type: String
    },
    place: {
        type: String
    },
    age: {
        type: Number
    },
    blocked: {
        type: Boolean,
        default: false
    },
    problem: [
        {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'Problem'
        },
    ],
    solution: [
        {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'Solution'
        }
    ],
    comment: [
        {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'Comment'
        }
    ]
})

and Comments Schema:

const commentSchema = new mongoose.Schema({
    content: {
        type: String,
        required: [true, 'You have to enter a content']
    },
    createdAt: {
        type: Date,
        default: Date.now()
    },
    isFunctional: {
        type: Boolean,
        default: false
    },
    user: {
        type: mongoose.Schema.Types.ObjectId,
        required: true,
        ref: 'User'
    },
    problem: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Problem'
    },
})


module.exports = mongoose.model('Comment', commentSchema)

In my project, I send problems into MongoDB. Then I send comment. After save comments, I add these comments into problems and user DB with a function.

function that comments are saved in DB:

const Comment = require('../models/comment/Comment')
const Problem = require('../models/problem/Problem')
const User = require('../models/user/User')
const asyncErrorWrapper = require('express-async-handler')

const addCommentToProblem = asyncErrorWrapper(async (req, res, next) => {

    const {content, problemId} = req.body
    
    const newComment = await Comment.create({
        content: content,
        problem: problemId,
        user: req.user.id,
    })

    const problemOfComment = await Problem.findByIdAndUpdate(problemId, {
        $push: { comment: newComment._id }
    })

    const userOfComment = await User.findByIdAndUpdate(req.user.id, {
        $push: { comment: newComment._id }
    })

})

Okey everything is so far so good. The problem comes here. When I try to get a problem, I populate some fields for example user fields. So I can add user information in this detail of problem. When populate user and comment in problem schema, it sends me the data. Still, we're ok. But when I try to get user field in comments, it doesn't populate user. It turns just objectId of user information.

Here is the function that I get problem:

const getAProblem = asyncErrorWrapper(async (req, res, next) => {

    const {id} = req.params

    const problems = null

    await Problem.findByIdAndUpdate(id, {
        $inc: { views: 1 }
    }, { new: true })
    .populate('user') ==> THIS LINE WORKS
    .populate('comment') ==> THIS LINE WORKS
    .populate('comment.user') ==> THIS LINE DOES NOT WORK
    .exec(function(err, post) {
        if(err) {
            console.log(err)
        }
        
        res
        .status(200)
        .json({
            success: true,
            data: post
        })
    });

})

Thanks for reading and your patience. Any help will be appreciated.


Solution

  • See doc at https://mongoosejs.com/docs/populate.html

    And try this way.

    const getAProblem = asyncErrorWrapper(async (req, res, next) => {
    
    const {id} = req.params
    
    const problems = null
    
    await Problem.findByIdAndUpdate(id, {
        $inc: { views: 1 }
    }, { new: true })
    .populate('user') ==> THIS LINE WORKS
    .populate({
       'path': 'comment',
       'populate': {
         'path':'user'
       }
    })
    .exec(function(err, post) {
        if(err) {
            console.log(err)
        }
        
        res
        .status(200)
        .json({
            success: true,
            data: post
        })
    });
    })