mongoosepopulate

Mongoose how to populate data within an object


I have read several topics here on Stack Overflow with the same question (How to populate in this case Mongoose), but I don't know why in my case it doesn't work at all.

I have a user model:

const UserSchema = new Schema({
  login: String,
  email: String,
  password: String,
  purchases: [{
    item: {
      type: Schema.Types.ObjectId,
      ref: 'cart'
    },
    quantity: {
      type: Number,
      default: 1
    }
  }
})];

Pay attention that purchases it's an array of objects (why objects? because I need an additional field 'quantity', so I was told here on SO how to implement this) that have additional field - quantity. I'm using push method on user.purchases to add new items and it work like a charm well so far. The main problem appears when I try to populate items inside 'purchases' array. I tried different ways:

    User.findById(userId).populate({
        path: 'purchases',
        populate: {
          path: 'item',
          model: 'product'
        }
    })

    User.findById(userId).populate({
        path: 'purchases.item',
        model: 'product',
    })
with and without 'model', was using populate('purchases') and etc., but everything was of no use...I alway get data with _id's of items instead of items data itself.

    {
        "_id": "5b60620689f0872a3010b726",
        "login": "lalal",
        "email": "ololo",
        "password": "hahahah",
        "purchases": [
            {
                "quantity": 1,
                "_id": "5b4b80c73c566508146b563f"
            },
            {
                "quantity": 1,
                "_id": "5b4b80c73c566508146b5640"
            },
            {
                "quantity": 1,
                "_id": "5b4b80c73c566508146b5643"
            }
        ],
        "__v": 3
    }

What I'm doing wrong, or maybe I made a mistake with a schema itself?

UPD.: I made single file test, result the same but now the whole code here. Could someone fix or explain what's wrong with this code? :

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

const UserSchema = new Schema({
    name: String,
    age: Number,
    items: [{
        buy: {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'product'
        },
        quantity: {
            type: Number,
            default: 1
        }
    }]
});

const ProductSchema = new Schema({
    title: String,
    price: Number
});

const Product = module.exports.product = mongoose.model('product', ProductSchema);
const User = module.exports.user = mongoose.model('user', UserSchema);


const newProduct = new Product({
    title: 'Ferrari',
    price: 10000
});

const newUser = new User({
    name: 'Jim',
    age: 20
});

newUser.items.push(newProduct);
newUser.save().then(async () => {
    const data = await User.findOne({name: 'Jim'})
        .then(user => {
            return user.populate({
                path: 'items',
                populate: {
                    path: 'buy',
                    model: 'product'
                }
            });
        });
    console.log(data);
});

mongoose.connect('mongodb://127.0.0.1:27017/megatest')
    .then(() => {
        mongoose.connection.collections.users.drop();
    });

Solution

  • Well let's get it that way the models.

    user.js

    const mongoose = require('../database/index')
    const UserSchema = new mongoose.Schema({
        login: String,
        email: String,
        password: String,
        purchases: [{
          item: {
            type: mongoose.Schema.Types.ObjectId,
            ref: 'Cars'
          },
          quantity: {
            type: Number,
            default: 1
          }
        }]
    })
    
    module.exports = mongoose.model('User', UserSchema)
    

    cars.js

    const mongoose = require('../database/index')
    const carSchema = new mongoose.Schema({
        name:{
            type: String
        },
        tipo: {
            type: String
        }
    })
    
    module.exports = mongoose.model('Cars', carSchema)
    

    As the item is a list of purchases it does not populate just by saying that it is the purchases.

    app.get('/busca', async (req, res) => {
        const user = await User.findById({_id:'5b6090516311531fd0b3daaa'}).populate('purchases.item')
        res.send(user)
    })
    

    Here is the key point, to say for the popular mongoose the list inside purchases. .populate('purchases.item')

    Result

    {
        "_id": "5b60927c79a13f1c98b0aca9",
        "login": "adm",
        "email": "example@example.com",
        "password": "123456",
        "purchases": [
            {
                "quantity": 1,
                "_id": "5b60927c79a13f1c98b0acaa",
                "item": {
                    "_id": "5b60927379a13f1c98b0aca8",
                    "name": "ferrari",
                    "tipo": "sedan",
                    "__v": 0
                }
            }
        ],
        "__v": 0
    }
    

    EDIT: In this way too populates correct, choosing some item in the search.

    app.get('/busca', async (req, res) => {
        //const user = await User.findById({_id:'5b60927c79a13f1c98b0aca9'}).populate('purchases.item', 'tipo')
        const user = await User.findById({_id:'5b60927c79a13f1c98b0aca9'}).populate({
            path: 'purchases.item',
            select: 'name'
        })
        res.send(user)
    })