node.jsexpressmongoosepopulate

Unable to populate my fields using populate()


This is my product.js model

const mongoose = require("mongoose");
const { Schema } = mongoose;

const productsSchema = new mongoose.Schema({
    name: {
        type: String,
        required: [true, "Name is required"]
    },
    imgURL: {
        type: String,
        required: [true, "imgURL is required"]
    },
    description: {
        type: String,
        required: [true, "Description is required"]
    },
    categoryName: {
        type: String,
        required: [true, "Category is required"]
    },
    price:{
        type: Number,
        required: [true, "Price is required"],
        default: false
    },
    isActive:{
        type: Boolean,
        default: true
    },
    variations: {
        size:[
            {
            type: Schema.Types.ObjectId,
            ref: 'Size'
            }
        ]
    }
})

const Products = mongoose.model('Products', productsSchema);

module.exports = Products;

and here's my code:

const Products = require("../models/products");
const Size = require("../models/size")

module.exports.createProduct = (req,res) => {
    if (!req.user.isAdmin) {
        return Promise.reject("Only administrators can create products")
    }

    const newProduct = new Products ({
        name: req.body.name,
        imgURL: req.body.imgURL,
        description: req.body.description,
        categoryName: req.body.categoryName,
        isActive: req.body.isActive,
        price: req.body.price
    });

    return newProduct.save()
    .then(() => {
        return res.send(true);
    })
    .catch((error) => {
        console.error(error);
        if (error.name === 'ValidationError') {
            return res.status(400).json({message: 'Validation Error', errors: error.errors});
        }
        return res.status(500).json({message: 'Internet server error'});
    });
};


module.exports.getAllActiveProducts = (req, res) => {
    Products.find({ isActive: true })
            .populate({ path: 'variations.size', model: 'Size'})

        .then(result => {
            console.log("Found products with variations:", result);
            return res.send(result);
        })
        .catch(err => {
            console.error("Error fetching active products:", err);
            return res.status(500).json({ error: "Failed to fetch active products" });
    });
};

This is my Size model

const mongoose = require("mongoose");

const sizeSchema = new mongoose.Schema({
    name: {
        type: String,
        required: [true, "Size is required"]
    },
    isActive: {
        type: Boolean,
        default: true
    }
})

const Size = mongoose.model('Size', sizeSchema);

module.exports = Size;

I want to populate my size field, but it seems I am having a problem with the connection of my model (Size) because it returns blank array.

View my Postman screenshot

I already used ref and populate to populate my size field but doesn't work.

Sizes collection: Screenshhot


Solution

  • In your Product model add this removing your existing variations.

    variations: [
                {
                type: Schema.Types.ObjectId,
                ref: 'Size'
                }
            ]
    

    Then create Product like this.Try using async((req,res) =>{.. Since my code is aligned with this approach.

    const Products = require('./path_to_product_model');
    const Size = require('./path_to_size_model');
    
    //create "Size" Documents
     
    const smallSize = new Size({ name: 'Small' });
    const mediumSize = new Size({ name: 'Medium' });
    
    await smallSize.save();
    await mediumSize.save();
    
    //create "Product" Document
     const newProduct = new Products ({
        name: req.body.name,
        imgURL: req.body.imgURL,
        description: req.body.description,
        categoryName: req.body.categoryName,
        isActive: req.body.isActive,
        price: req.body.price ,
        variations: [smallSize._id, mediumSize._id]
    });
    
    await newProduct.save();
    

    To retrieve a Product and populate its variations field with the corresponding Size documents do this,

    const product = await Products.find({ isActive: true}).populate('variations');
    

    Try this.It will work.

    For more information on populate() you can visit the doc link given below.

    https://mongoosejs.com/docs/populate.html#saving-refs

    N:B :- In the above code block I have used async-await to get Promise based data. If you want you can change accordingly.