mongoose .populate() is not populating even with variable set to ObjectId - mongodb

Here is my model for "product" schema:
const productSchema = new Schema({
productName: String,
productCategory: {
type: Schema.Types.ObjectId,
ref: "category",
},
productPrice: Number,
productImageUrl: String,
});
Here is the router for the GET method:
router.get("/", async (req, res) => {
try {
const products = await ProductModel.find().populate("category");
res.status(200).json({ erorr: false, products });
} catch (err) {
res.status(500).json({ error: true, err });
}
});
What I actually get is this:
"error": false,
"products": [
{
"_id": "6009f4bfd397734920c93ce8",
"productName": "Milk",
"productCategory": "6009d244332f2f22c40f90b4",
"productPrice": 8,
"productImageUrl":""
In Mongo Compass I can see that "productCategory" is set with ObjectId value.
Any ideas what am I doing wrong?
Thanks!

Try this one:
const mongoose = require('mongoose');
const Types = mongoose.Schema.Types;
const productSchema = new Schema({
productName: String,
productCategory: {
type: Types.ObjectId,
ref: "category",
},
productPrice: Number,
productImageUrl: String,
});
const products = await ProductModel.find({}).populate({path:"productCategory"});

you should put the key that has ref to populate like this:
const products = await ProductModel.find().populate("productCategory");

Related

How can I see the products per each category with mongoose

this is my schema for storing products using mongoose as below.
const mongoose = require("mongoose");
const mongoosePaginate = require("mongoose-paginate-v2");
const productSchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
name: {
type: String,
required: true,
},
category: {
type: mongoose.Schema.Types.ObjectId,
ref: "Category",
},
productImage: {
type: String,
required: true,
},
description: {
type: String,
},
createdAt: {
type: Date,
default: new Date(),
},
deletedAt: {
type: Date,
},
});
productSchema.plugin(mongoosePaginate);
const productModel = mongoose.model("Product", productSchema, "Product");
module.exports = productModel;
and this how I have the schema for storing categories that products are related to
const mongoose = require("mongoose");
const categorySchema = mongoose.Schema({
_id: mongoose.Schema.Types.ObjectId,
product: { type: mongoose.Schema.Types.ObjectId, ref: "Product" },
});
const categoryModel = mongoose.model("Category", categorySchema, "Category");
module.exports = categoryModel;
What I don´t know is how to populate my controller.
getAll: async (req, res) => {
const limitPage = parseInt(req.query.limit, 10) || 10;
const pageChange = parseInt(req.query.page, 10) || 1;
Product.paginate({}, { limit: limitPage, page: pageChange })
.then((result) => {
return res.status(200).json({
message: "GET request to all getAllProducts",
dataCount: result.length,
result: result,
});
})
.catch((err) => {
console.log(err);
res.status(500).json({
error: err,
});
});
},
Please help, I don´t understand why it not being populated and how to see the categories displayed with the categorie they belong to.
You should probably include populate in your query like so:
...
Product.paginate({}, { limit: limitPage, page: pageChange }).populate('category')
...
Note: Are you sure you want to have a 1-1 relation between products and categories. Because this is what you achieve if you set the relation like you did on both schemas. If yes, you should find a way to ensure that this 1-1 relation is enforced each time you save or update objects.

mongoose: Add an element into an empty child array under

I have the following schema, and I have a document of the story in mongodb, this story doesn't have values for key "fans", which is an array.
I would like to add an element to this array. However, I tried to use fans.push, fans.pop or fans = [element], it doesn't work. Please help me to understand what is the best way of doing this.
const personSchema = Schema({
_id: Schema.Types.ObjectId,
name: String,
age: Number,
stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
const storySchema = Schema({
author: { type: Schema.Types.ObjectId, ref: 'Person' },
title: String,
fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});
const Story = mongoose.model('Story', storySchema);
const Person = mongoose.model('Person', personSchema);
const story1 = new Story({
title: 'Casino Royale',
author: author._id // assign the _id from the person
});
const fan = new Person({
_id: new mongoose.Types.ObjectId(),
name:'Fan 001',
age:38
});
fan.save(function(err){
if (err) return handleError(err);
const story1=Story.findOne({title:'Casino Royale'});
story1.fans=[fan._id];
story1.save(function (err){
if (err) return handleError(err);
});
});
when I run this script, I have got the following error:
So to make this whole thing work you need a few steps:
Step 1: You need to save the story1 you created else the findOne wont return anything
Step 2: You need to await database calls since they are async
I will provide a code making use of the database update methods, it is a lot cleaner and faster to directly push it in the database.
So here is your code corrected:
const personSchema = Schema({
_id: Schema.Types.ObjectId,
name: String,
age: Number,
stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
const storySchema = Schema({
author: { type: Schema.Types.ObjectId, ref: 'Person' },
title: String,
fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});
const Story = mongoose.model('Story', storySchema);
const Person = mongoose.model('Person', personSchema);
const author = { name: 'asdsd', _id: "aaaaaaaaaaaaaaaaaaaaaaaa" } // Note I hardcoded an id here
const story1 = new Story({
title: 'Casino Royale',
author: author._id // Assign the _id from the person
});
await story1.save() // Await
const fan = new Person({
_id: new mongoose.Types.ObjectId(),
name: 'Fan 001',
age: 38
});
await fan.save(async function(err) { // Await since we have to await the database
if (err) return handleError(err);
const story1 = await Story.findOne({ title: 'Casino Royale' }); // Await database
console.log(story1)
story1.fans.push(fan._id);
await story1.save(function(err) { // Await again
if (err) return handleError(err);
});
});
Here is the code in a better version (Note that the schema doesnt have an _id anymore since it is provided by mongoDb):
const personSchema = Schema({
name: String,
age: Number,
stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});
const storySchema = Schema({
author: { type: Schema.Types.ObjectId, ref: 'Person' },
title: String,
fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});
const Story = mongoose.model('Story', storySchema);
const Person = mongoose.model('Person', personSchema);
const author = { name: 'asdsd', _id: "aaaaaaaaaaaaaaaaaaaaaaaa" } // Note I hardcoded an id here
// Create a Story that is immediately saved in the database and gets an _id by mongoDb
await Story.create({
title: 'Casino Royale',
author: author._id
})
// Create a Person that is immediately saved in the database and gets an _id by mongoDb
const fan = await Person.create({
name: 'Fan 001',
age: 38
})
// Add the Person to the stories fans array
const story1 = await Story.findOneAndUpdate(
{ title: 'Casino Royale' },
{ $push: { 'fans': fan._id } },
{ new: true })
console.log(story1)
here const story1=Story.findOne({title:'Casino Royale'}); findOne is not returning the document hence save is not defined for that.
as mentioned in the documentation it returns a query
try writing your code using promise and await for the response
const story1 = await Story.findOne({title:'Casino Royale'});

How do I find with reference of a MongoDB model

I am trying to find the ID of a model which is a reference to another model. I have a shopModel and a productModel that has a reference to shopModel
//shopModel
const shopSchema = mongoose.Schema({
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "User",
},
name: {
type: String,
},
description: {
type: String,
}
})
//productModel
const productSchema = mongoose.Schema(
{
shop: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "Shop",
},
name: {
type: String,
required: true,
},
//and more
Now my question is do I use await Product.find({ shop: "shopID"}) or await Product.findById(req.params.id). The current route is /shop/shopID. Note that there will be multiple shops and multiple products in one shop, but no shop will have the same productID. The problem now is I tried to console.log await Product.findById(req.params.id) and turned up undefined. Any help would be appreciated. Thank you.
UPDATE
//current productController
const getProducts = AsyncHandler(async (req, res) => {
const shopID = await Product.findOne({
shop: req.params.id,
});
console.log(shopID._id);
const products = await Product.find({
shop: mongoose.Types.ObjectId(req.params.id),
});
res.json({ products });
});
The output log is the product ID
//new productController
const getProducts = AsyncHandler(async (req, res) => {
const shopID = await Shop.findOne({
shop: req.params.id,
});
console.log(shopID._id);
const products = await Product.find({
shop: mongoose.Types.ObjectId(req.params.id),
});
res.json({ products });
});
Now I am getting the shop ID. I created 2 test shops, shop1 has all the products, while shop2 has none. The current problem is the log for both shops is giving the same id.

Save() not saving nested properties

I am new in mongo. I need to update one nested field in MongoDB model. This is my code: -
const employee = await empModel.searchData(Query);
countryArray.push({lang: 'eng', result 100});
countryArray.push({lang: 'german', result 99});
employee[0].country = countryArray;
employee[0].markModified('country');
employee[0].save();
Schema of empModel:
onst mongoSchema = new Schema({
empId: [{
type: Schema.Types.ObjectId
}],
country:[{
lang:String,
result:Number
}],
projectId: {
type: String,
required: true
}
});
Use simple update query instead of find and the update
static async updateData(query, countryArray) {
const updateData= await this.update(query, { $set: { country: countryArray }});
console.log(updated successfully')
return 'Updated successfully'
}
const countryArray = []
countryArray.push({lang: 'eng', result 100})
countryArray.push({lang: 'german', result 99})
const update = await empModel.updateData(Query, countryArray)

Mongoose .pull not deleting subdocument

I'm trying to remove a product from a category using mongoose .remove from these other questions but none seem to work
Remove sub-document from Mongo with mongoose
But nothing is happening and I only get back the same thing unedited
Category Schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const Product = require('./Product');
const CategorySchema = Schema({
_id: Schema.Types.ObjectId,
categoryName: {
type: String,
required: true,
},
categoryDescription: String,
productList: [Product],
});
mongoose.model('Category', CategorySchema);
Products Schema
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ProductSchema = Schema({
productName: {
type: String,
required: true,
},
productDescription: String,
categories: { type: Schema.Types.ObjectId, ref: 'Category' },
});
mongoose.model('Product', ProductSchema);
My express route to handle deleting of the subdocument
app.delete('/api/category-with-product/:categoryId', (req, res) => {
const categoryId = req.params.categoryId;
const { productId } = req.body;
Category.findById(categoryId)
.then((category) => {
category.productList.pull({ _id: productId });
return category.save();
})
.then((newCategory) => {
res.send(newCategory);
});
});
My expected outcome is for this is to just remove the product in the productList array
{
_id: 5c5b990d56b3f61ce3736e6f,
categoryName: 'A new category name',
description: 'description',
productList:[
{ _id: 5c6e4b5114333b25f8e9d737,
productName: 'test',
productDescription: 'test'
}
],
}
Could you please try this:
const ObjectId = mongoose.Types.ObjectId;
function funcName() {
return new Promise((resolve, reject) => {
db.category.update(
{ },
{ $pull: { productList: { _id: ObjectId(productId) } } },
{ multi: true }
)
.then((result) => resolve())
.catch((err) => reject(err));
});
}
You can also try Async/Await during database operations.