Search code examples
node.jsmongodbmongoosemongoose-populate

Mongoose populate does not populate


I have two collections into my MongoDB database: users and components.

The users' primary key is _id which is Number. It is referenced by the created_by and updated_by fields of a component document.

Everything works well except for the populate and I can't figure it out why. It leaves the value instead of the corresponding user document. I also tried to use ObjectIds instead of Numbers but nothing changed.

Any help will be appreciated.

I listed above the models and routing sources.

Component and User models

models/user.js

import mongoose from 'mongoose';

const userSchema = new mongoose.Schema({
    _id: Number,
    firstName: String,
    lastName: String,
    email: String,
    password: String,
});

const User = mongoose.model('User', userSchema);

export default User;

models/component.js

import mongoose from 'mongoose';

const componentSchema = new mongoose.Schema({
    name: String,
    category: String,
    package: String,
    box: Number,
    cell: Number,
    quantity: Number,
    note: String,
    link: String,
    created_by: {
        type: Number,
        ref: 'User'
    },
    created_on: Date,
    updated_by: {
        type: Number,
        ref: 'User'
    },
    updated_on: Date
});

const Component = mongoose.model('Component', componentSchema);

export default Component;

models/index.js

import Component from './component';
import User from './user';

const models = { Component, User };

export default models;

Middleware

import models from './models';

app.use((req, res, next) => {
    req.context = { models };
    next();
});

Components routing

import { Router } from "express";
const router = Router();
...
var getComponents = async (req, res) => {
    const query = req.context.models.Component.find().populate('users');

    try {
        const results = await query;
        return res.status(200).send({ results: results });
    } catch (err) {
        return res.status(400).send({ error: err });
    }
}
...
router.get('/', getComponents)

export default router;

I also tried to use the exec

var getComponents = (req, res) =>
    req.context.models.Component.find().populate('users').exec().then(components => res.status(200).send({ results: components })).catch(err => res.status(400).send({ error: err }));

but I got the same result.


Solution

  • You just need to use an existing field name in populate path like .populate('created_by')

    Here is the test:

    I first created a user with this request body:

    {
        "_id": 111,
        "firstName": "John",
        "lastname": "River",
        "email": "abc@def.net",
        "password": "123123"
    }
    

    Then I created two components:

    {
        "name": "component 1",
        "quantity": 1,
        "created_by": 111
    }
    

    And

    {
        "name": "component 2",
        "quantity": 2,
        "created_by": 111
    }
    

    And using this code:

    const result = await Component.find().populate("created_by");
    

    The result is:

    [
        {
            "_id": "5de7a89e9039c738b4008d41",
            "name": "component 1",
            "quantity": 1,
            //other fields
            "created_by": {
                "_id": 111,
                "firstName": "John",
                "email": "abc@def.net",
                "password": "123123",
                "__v": 0
            },
            "__v": 0
        },
        {
            "_id": "5de7a8aa9039c738b4008d42",
            "name": "component 2",
            "quantity": 2,
            //other fields
            "created_by": {
                "_id": 111,
                "firstName": "John",
                "email": "abc@def.net",
                "password": "123123",
                "__v": 0
            },
            "__v": 0
        }
    ]