Search code examples
javascriptnode.jsmongodbexpressmongoose

How do I link two models in mongoose?


There are two models, ProductModel and CategoryModel.

Purpose: When creating a product (ProductModel), assign a category to it, respectively, an array of products should be filled in the category collection, but the connection between them does not work. When creating a product (ProductModel), I output the response via json, it contains all fields except the category field, I need this field to be filled in too.

Product Model

import { Schema, model } from 'mongoose'

const ProductModel = new Schema({
    productName: { type: String, required: true },
    price: { type: Number, required: true },
    preview: { type: String },
    color: { type: String, required: true },
    specs: {
        images: [{ type: String }],
        memory: { type: Number },
        ram: { type: Number },
        diagonal: { type: String },
    },
    category: {
        name: String,
        type: Schema.Types.ObjectId,
        ref: 'Category',
    },
})

export default new model('Product', ProductModel)

CategoryModel

import { Schema, model } from 'mongoose'

const CategoryModel = new Schema({
    name: {
        type: String,
        required: true,
    },
    products: [
        {
            type: Schema.Types.ObjectId,
            ref: 'Product',
        },
    ],
})

export default new model('Category', CategoryModel)

The logic of the product creation route

  async post(req, res, next) {
        try {
            // Get fields from client
            let { productName, price, preview, color, specs, category } = req.body

            // Looking for a category transferred from a client
            const productCategory = await CategoryModel.find({ name: category })
            console.log(productCategory)

            // Creating product
            const doc = new ProductModel({
                productName,
                price,
                preview,
                color,
                specs,
                category: productCategory._id,
            })

            // Save product
            const product = await doc.save()

            // Returning a response from the server to the client
            return res.json(product)
        } catch (error) {
            console.log(error.message)
        }
    }

Here is what I send to the server and receive from it

Request:
{
    "productName": "Air pods pro",
    "price": 123,
    "preview": "preview",
    "color": "red",
    "specs": {
        "images": ["image1, image2, image3"],
        "memory": 64,
        "ram": 16,
        "diagonal": "diagonal"
    },
    "category": "AirPods"
}

Response:
{
    "productName": "Air pods pro",
    "price": 123,
    "preview": "preview",
    "color": "red",
    "specs": {
        "images": [
            "image1, image2, image3"
        ],
        "memory": 64,
        "ram": 16,
        "diagonal": "diagonal"
    },
    "_id": "6609ad76341da85122e029d0",
    "__v": 0
}

As you can see, there is no category field in the response, just like in the database, this field is missing in each product. And the Category collection, which has an array of products, is also not filled

I will attach screenshots below

Mongo Mongo


Solution

  • In your ProductModel schema the category property has a name property given to it. That suggests you want category to be an Object with a name property. I pressume that was not your intention. You need to remove that so that category is just a property with a value of type ObjectId.

    const ProductModel = new Schema({
        //...
        category: {
            name: String, //< delete this
            type: Schema.Types.ObjectId,
            ref: 'Category',
        },
    })
    

    To get the product._id into the productCategory.products array you need to manually push it to the array like so:

    const productCategory = await CategoryModel.find({ name: category })
    console.log(productCategory)
    
    // Creating product
    const doc = new ProductModel({
       productName,
       price,
       preview,
       color,
       specs,
       category: productCategory._id,
    })
    
    // Save product
    const product = await doc.save()
    
    // Now save product._id into productCategory.products array
    productCategory.products.push(product._id);
    await productCategory.save();
    
    // Returning a response from the server to the client
    return res.json(product)