Mongoose populate returning data without population - node.js

I know that this question was asked many many times but i still can't find a solution
So this is my db
Product :
Ingredient :
Schemas :
ingredient.js
const mongoose = require("mongoose");
var IngredientSchema = new mongoose.Schema({
quantity: {
value: Number,
unit: String
},
comment: String,
product: { type: mongoose.Schema.Types.ObjectId, ref: "Product" }
});
module.exports = mongoose.model("IngredientSchema", IngredientSchema);
product.js
const mongoose = require("mongoose");
var ProductSchema = new mongoose.Schema({
name: {
type: String,
default: "",
trim: true,
required: "Name cannot be blank"
},
category: {
type: String,
default: "",
trim: true
},
convertion: [
{
unit_from: String,
unit_to: String,
value_from: Number,
value_to: Number
}
],
default_unit: String
});
const Product = (module.exports = mongoose.model(
"ProductSchema",
ProductSchema
));
this is the populate function :
ingredientRoutes.route("/:id").get(function(req, res) {
let id = req.params.id;
Ingredient.findById(id)
.populate("produit")
.exec()
.then(function(data) {
console.log(data.product, "***");
})
.catch(function(err) {
console.log(err);
});
});
this is the result that i'm getting :
just the id of the product without making the population
Any idea ?

Related

MongoDB Auto-increment for a nested Object in a document in Node.js

I've a schema in Mongo like below:
({
title: String,
genre: String,
publishDate: Date,
index:Number,
requirementInformation:{
requirementInformationStatus:{
type: String,
required: true
},
requirement: [{ requirementId: {
type: Number
},requirementState: {
type: String
}}]
}
})
I want to Auto-increment the field requirementId in Node.js. I tried using mongoose-auto-increment package but not able to create the Auto-increment for the nested Object. Need some help.
My code is as below:
const mongoose = require('mongoose')
const Schema= mongoose.Schema;
var autoIncrement = require('mongoose-auto-increment');
var connection = mongoose.createConnection("mongodb://localhost/Test");
autoIncrement.initialize(connection);
var bookSchema = new Schema({
title: String,
genre: String,
publishDate: Date,
index:Number,
requirementInformation:{
requirementInformationStatus:{
type: String,
required: true
},
requirement: [{ requirementId: {
type: Number
},requirementState: {
type: String
}}]
}
});
bookSchema.plugin(autoIncrement.plugin, {model:'Book',field: 'requirementInformation.requirement.requirementId'});
//authorSchema.plugin(autoIncrement.plugin, 'Author');
var Book = connection.model("Book", bookSchema);
const me = new Book({
title: 'MyBook',
requirementInformation:{requirementInformationStatus:'True',requirement:[{requirementState:"hj"}]}
})
me.save().then(() => {
console.log(me)
}).catch((error) => { console.log(error) })
How can I access the requirementId field?

It says items is undefined

The code is show below.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const user = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
resetToken: String,
resetExpiration: String,
products: [{type: mongoose.Types.ObjectId, required: true, ref: 'Shop'}],
cart: {
items: [
{
productId: {type: mongoose.Types.ObjectId, ref: 'Shop', required: true},
quantity: {type: Number, required: true},
}
]
},
});
user.methods.addToCart = (product) => {
const itemIndex = this.cart.items.findIndex(prod => {
return prod.productId.toString() === product._id.toString();
});
let newQuantity = 1;
const updatedCartItems = [...this.cart.items];
if(itemIndex >= 0) {
newQuantity = this.cart.items[itemIndex].quantity + 1;
updatedCartItems[itemIndex].quantity = newQuantity;
} else {
updatedCartItems.push({
productId: product,
quantity: newQuantity
});
}
const updatedCart = {
items: updatedCartItems
}
this.cart = updatedCart;
return this.save();
}
const model = mongoose.model('User', user);
module.exports = model;
I am trying to store product in the cart instance method as per above schema, but when i send product from my controller to addToCart it says items is undefined on this.cart.items. I haven't used instance method much in mongoose so, i don't know this issue is it with schema or general problem.
let me know if you need any other information.
It was a silly mistake, actually i was using arrow function. so it wasn't bind to schema.

Product.find({category: req.params.category}) doesn't work

Now in product schema, I have a category attached to it like that
"_id" : ObjectId("5e6dfde62764a11b34ccc9a3"),
"title" : "t-shirt",
"price" : 12,
"category" : "T-shirts",
"description" : "<p>tshirts description goes here</p>\r\n",
"images" : [ ],
"__v" : 0
and my route is like that:
router.get('/category/:category', function(req, res){
var categorySlug = req.params.category;
Category.findOne({slug: categorySlug}, function(err, category){
if(err){
console.log(err);
} else {
Product.find({category: categorySlug}, function(err, products){
if(err){
console.log(err);
} else {
console.log(category)
console.log(products)
res.render('client/cat_product', {products, category, title: products.title});
}
})
}
})
})
The problem is:
when I console.log(category) it displays the category normally but when I console.log(products) it gives me a blank array with no products in it
these are the schema models for the category and the product:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const CategorySchema = new Schema({
title: {
type: String,
required: true
},
slug: String,
products: [
{
type: Schema.Types.ObjectId,
ref: 'Product'
}
]
});
const Category = mongoose.model('Category', CategorySchema);
module.exports = Category;
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ProductSchema = new Schema({
title: {
type: String,
required: true
},
description: {
type: String,
required: true
},
category: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
images: [
{
url: String,
public_id: String
}
]
});
module.exports = mongoose.model('Product', ProductSchema);
I believe this solution may work, if not, please, let me know what you see as output. I was able to test the solution on a simple problem I have created, but I have no idea regarding the details of yours, your question does not leave it clear, and you did not provide further details.
router.get("/category/:category", function(req, res) {
var categorySlug = req.params.category;
res.send(
res.render("client/cat_product", {
products: await Product.find({ category: categorySlug }) ,
category: await Category.findOne({ slug: categorySlug }) ,
title: await await Product.find({ category: categorySlug }).select("title")
})
);
});
If you have several products, coming from Category.findOne, you may need to do something like Category.findOne().populate("products").
Hope that helps!

How to access nested data which is a reference data in an array in mongoose?

So I have this nested data object which is also a reference data. When I try to access it using populate it is showing only the id. I do not want only the id. I also want the details to come along. Can someone please help me on this?
This is the EmployeesDetailsSchema which have this employeesinfo property with a reference in it. Now the designation and speciality property as you can see in the image is coming only in ids and not the full details i want the full the details of these two as well as the other fields also.
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const EmployeesDetailsSchema = new Schema({
employeesinfo: {
type: mongoose.Schema.Types.ObjectId,
ref: "employees"
},
workingdays: Number,
fathersname: String,
pan: String,
joiningdate: Date,
gender: String,
pfno: String,
esino: String,
branchname: String,
department: String,
paymode: String,
bankname: String,
acno: String,
ifscno: String,
//Earnings
basicsalary: Number,
extra: Number,
totalE: Number,
//Days
fixeddays: Number,
presentdays: Number,
absentdays: Number,
leavedays: Number,
holidays: Number,
//Deductions
pf: Number,
esi: Number,
professionaltax: Number,
advance: Number,
absentdeductions: Number,
leavedeductions: Number,
totalD: Number,
//Net pay Details
netpay: Number,
inwords: String,
name: String,
date: {
type: Date,
default: Date.now
}
});
module.exports = EmpDetails = mongoose.model(
"empdetails",
EmployeesDetailsSchema
);
This is the EmployeesSchema which is reference in the employeesinfo property of the EmployeesDetailsSchema
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const EmployeesSchema = new Schema({
name: { type: String },
email: { type: String },
speciality: {
type: mongoose.Schema.Types.ObjectId,
ref: "speciality"
},
contactno: { type: Number },
designation: {
type: mongoose.Schema.Types.ObjectId,
ref: "designation"
},
alternatecontactno: { type: Number },
address: { type: String },
employeeImage: { type: String },
imageName: { type: String },
date: { type: Date, default: Date.now() }
});
module.exports = Employees = mongoose.model("employees", EmployeesSchema);
And these are the two models which is being reference in the EmployeesSchema
//Speciality Type Schema
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const SpecialitySchema = new Schema({
speciality: {
type: String
},
description: {
type: String
}
});
module.exports = Speciality = mongoose.model("speciality", SpecialitySchema);
//Designation Type Schema
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const DesignationSchema = new Schema({
designation: {
type: String
},
description: {
type: String
}
});
module.exports = Designation = mongoose.model("designation", DesignationSchema);
And this is the get route
router.get("/", (req, res) => {
EmpDet.find()
.populate({
path: "employeesinfo"
})
.then(empdet => res.json(empdet))
.catch(err =>
res.status(400).json({ msg: "Error in finding Employees Details" })
);
});
Populate usually returns the entire referred document if there is no specific options set. It can be used like this:
const story = await Story.findOne({ title: 'Some Titel' }).populate('authors');
See full documentation and further samples:
https://mongoosejs.com/docs/populate.html
Try this:
EmpDet.find()
.populate({
path: "employeesinfo",
populate: [
{ path: 'speciality' },
{ path: 'designation' }
]
})
.then(empdet => res.json(empdet))
.catch(err =>
res.status(400).json({ msg: "Error in finding Employees Details" })
);
Also, please have a look at the documentation too as mentioned by Simon.
https://mongoosejs.com/docs/populate.html

How to implement partial document embedding in Mongoose?

I have a simple relation between topics and categories when topic belongs to a category.
So schema looks like this:
const CategorySchema = new mongoose.Schema({
name: String,
slug: String,
description: String
});
And topic
const TopicSchema = new mongoose.Schema({
category: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Category'
},
title: String,
slug: String,
body: String,
created: {type: Date, default: Date.now}
});
I want to implement particular embedding of category into topic
{
category: {
_id: ObjectId('abc'),
slug: 'catslug'
},
title: "Title",
slug: "topictitle",
...
}
It will help me avoid unnecessary population and obtain performance bonuses.
I don't want to embed whole document because I want to changes categories sometimes (it is a rare operation) and maintain references.
Hope this helps, done it in my own project to save some RTTs in common use cases. Make sure you're taking care of both copies on update.
parent.model.js:
const mongoose = require('mongoose');
const childEmbeddedSchema = new mongoose.Schema({
_id: {type: mongoose.Schema.Types.ObjectId, ref: 'Child', auto: false, required: true, index: true},
someFieldIWantEmbedded: {type: String}
});
const parentSchema = new mongoose.Schema({
child: { type: childEmbeddedSchema },
moreChildren: { type: [{type: childEmbeddedSchema }] }
});
module.exports = mongoose.model('Parent', parentSchema);
child.model.js:
const mongoose = require('mongoose');
const childSchema = new mongoose.Schema({
someFieldIWantEmbedded: {type: String},
someFieldIDontWantEmbedded: {type: Number},
anotherFieldIDontWantEmbedded: {type: Date}
});
module.exports = mongoose.model('Child', childSchema);
parent.controller.js:
const mongoose = require('mongoose');
const Parent = require('path/to/parent.model');
exports.getAll = (req, res, next) => {
const query = Parent.find();
// only populate if requested! if true, will replace entire sub-document with fetched one.
if (req.headers.populate === 'true') {
query.populate({
path: 'child._id',
select: `someFieldIWantEmbedded ${req.headers.select}`
});
query.populate({
path: 'moreChildren._id',
select: `someFieldIWantEmbedded ${req.headers.select}`
});
}
query.exec((err, results) => {
if (err) {
next(err);
} else {
res.status(200).json(results);
}
});
};

Resources