Mongoose populate() is returning an empty array - javascript

I am trying to use mongoose populate function but in response I am getting empty array. I know there are several questions talking about the same subject but none worked for my case.
My objective is to populate my Order document.
This is how my schemas are organized:
Menu.js
const mongoose = require("mongoose");
const { Schema } = mongoose;
const Food = require("./Food");
const Drink = require("./Drink");
const MenuSchema = new Schema({
code: {
type: mongoose.ObjectId,
required: true,
unique: true,
},
name: {
type: String,
required: true,
},
food: {
type: [Food.schema],
required: false,
},
drinks: {
type: [Drink.schema],
required: false,
},
type: {
type: String,
},
createdAt: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model("Menu", MenuSchema);
Note: Im using Food.schema and Drink.schema inside my Arrays instead of making a ref. Im storing the Food and Drink models inside of the Menu model
Food.js
const mongoose = require("mongoose");
const { Schema } = mongoose;
const FoodSchema = new Schema({
code: {
type: mongoose.ObjectId,
required: true,
unique: true,
},
description: {
type: String,
required: true,
},
ingredients: {
type: [],
required: false,
default: [],
},
stock: {
type: Number,
required: true,
},
type: {
type: String,
enum: ["starter", "main", "dessert"],
required: true,
},
price: {
type: Number,
required: true,
},
createdAt: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model("Food", FoodSchema);
Drink.js
const mongoose = require("mongoose");
const { Schema } = mongoose;
const DrinkSchema = new Schema({
code: {
type: mongoose.ObjectId,
required: true,
unique: true,
},
description: {
type: String,
required: true,
},
stock: {
type: Number,
required: true,
},
price: {
type: Number,
required: true,
},
createdAt: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model("Drink", DrinkSchema);
Order.js
const mongoose = require("mongoose");
const { Schema } = mongoose;
const OrderSchema = new Schema({
code: {
type: mongoose.ObjectId,
required: true,
unique: true,
},
type: {
type: String,
required: true,
enum: ["restaurant", "takeaway", "delivery"],
},
food: {
type: [{ type: mongoose.ObjectId, ref: "Food" }],
required: false,
default: [],
},
drinks: {
type: [{ type: mongoose.ObjectId, ref: "Drink" }],
required: false,
default: [],
},
orderValue: Number,
client_id: {
type: mongoose.ObjectId,
ref: "Client",
required: false,
},
createdAt: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model("Order", OrderSchema);
This is the controller where I'm trying to make my populate work. Whenever I remove the populate method I get the _id references for the Food and Drink arrays.
TableController.js
exports.getOrderFromTable = async (req, res) => {
const { code, tableCode } = req.params;
try {
const foundRestaurant = await Restaurant.findOne({ code: code });
const foundTable = foundRestaurant.tables.filter(
(table) => table.code == tableCode
);
console.log(foundTable[0].order_id);
const foundOrder = await Order.findOne({
_id: foundTable[0].order_id,
})
.populate("food")
.populate("drinks");
res.send(foundOrder);
} catch (err) {
res.json({ message: err });
}
};
And this is what the mongoose debugger returns when I run the controller:
Mongoose: restaurants.findOne({ code: new ObjectId("62a60dcb9fe25d276815675c") }, { projection: {} })
new ObjectId("62a60ece9fe25d27681567b7")
Mongoose: orders.findOne({ _id: new ObjectId("62a60ece9fe25d27681567b7") }, { projection: {} })
Mongoose: foods.find({ _id: { '$in': [ new ObjectId("62a60e039fe25d276815677d"), new ObjectId("62a60e169fe25d2768156785") ], [Symbol(mongoose#trustedSymbol)]: true }}, { skip: undefined, limit: undefined, perDocumentLimit: undefined, projection: {}})
Mongoose: drinks.find({ _id: { '$in': [ new ObjectId("62a60e259fe25d276815678d"), new ObjectId("62a60e3c9fe25d276815679c") ], [Symbol(mongoose#trustedSymbol)]: true }}, { skip: undefined, limit: undefined, perDocumentLimit: undefined, projection: {}})
And finally this is the JSON file I get when I do a GET http request using Postman:
{
"_id": "62a60ece9fe25d27681567b7",
"code": "62a60ece9fe25d27681567b6",
"type": "restaurant",
"food": [],
"drinks": [],
"orderValue": 25,
"createdAt": "2022-06-12T16:05:34.513Z",
"__v": 0
}
Thank you for any help. I've been really struggling with this method.

Related

Mongoose population problem, how to populate another document

How to populate comment's (postedBy, votes, replies) on get req of the feature. Each feature has comments and Each comment has postedBy, replies, votes
my feature controller for getting single Feature
exports.getSingleFeature = (req, res) => {
try {
const { slug } = req.params;
Feature.findOne({ slug: slug.toLowerCase() })
.populate("postedBy", " email _id username")
.populate("comments", "content postedBy votes replies")
.populate("comments.postedBy", "_id email username")
.populate("postedBy", "_id email username")
.populate("")
.exec((err, feature) => {
if (err) {
return res.status(400).json({
error: errorHandler(err),
return res.json(feature);
catch (error) {
return res.status(400).json({
error: error,
};
My comment controller-
exports.createComment = (req, res) => {
const { featureId } = req.params;
const { content } = req.body;
const postedBy = req.auth._id;
if (!content) {
return res
.status(400)
.send({ error: "Please provide a content with your comment." });
}
const comment = new Comment({
content,
postedBy,
});
comment.save((err, result) => {
if (err) {
return res.status(400).json({
error: errorHandler(err),
});
}
Feature.findByIdAndUpdate(
featureId,
{ $push: { comments: result } },
new: true }
).exec((err, result) => {
if (err) {
return res.json({
error: errorHandler(err),
});
}
});
return res.status(201).json(result);
});
};
My Feature Model -
const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema;
const featureSchema = new mongoose.Schema(
title: {
type: String,
required: true,
min: 5,
max: 40,
trim: true,
unique: true,
type: {
type: String,
trim: true,
description: {
type: String,
required: true,
min: 25,
max: 400,
trim: true,
slug: {
type: String,
unique: true,
index: true,
excerpt: {
type: String,
required: true,
min: 10,
max: 120,
trim: true,
postedBy: {
type: ObjectId,
ref: "User",
comments: [
type: ObjectId,
ref: "Comment",
likes: [{ type: ObjectId, ref: "User", required: true }],
timestamps: true }
module.exports = mongoose.model("Feature", featureSchema);
MY comment Model-
const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema;
const commentSchema = new mongoose.Schema(
{
content: {
type: String,
required: true,
trim: true,
max: 200,
},
postedBy: {
type: ObjectId,
ref: "User",
required: true,
},
votes: [
{
postedBy: {
type: ObjectId,
ref: "User",
},
created: {
type: Date,
default: Date.now,
},
},
],
replies: [
{
content: {
type: String,
required: true,
trim: true,
max: 200,
},
postedBy: {
type: ObjectId,
ref: "User",
},
created: {
type: Date,
default: Date.now,
},
votes: [
{
postedBy: {
type: ObjectId,
ref: "User",
},
created: {
type: Date,
default: Date.now,
},
},
],
},
],
},
timestamps: true }
);
module.exports = mongoose.model("Comment", commentSchema);```
I am getting this on postman -
enter image description here

MissingSchemaError: Schema hasn't been registered for model UserAddress.address

Been pulling my hair out for hours now, just can't figure out why the field refuses to populate.
What I want to do is return the AddressId field populated with values instead of just an ID, but nothing I've tried works, none of the solutions I found do anything.
If you need any other code from the project, I will update the question.
Any help is highly appreciated.
Order Model:
const mongoose = require("mongoose");
const orderSchema = new mongoose.Schema(
{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true,
},
addressId: {
type: mongoose.Schema.Types.ObjectId,
ref: "UserAddress.address",
required: true,
},
totalAmount: {
type: Number,
required: true,
},
items: [
{
productId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Product",
},
payablePrice: {
type: Number,
required: true,
},
purchasedQty: {
type: Number,
required: true,
},
},
],
paymentStatus: {
type: String,
enum: ["Pending", "Completed", "Cancelled", "Refund"],
required: true,
},
paymentType: {
type: String,
enum: ["CoD", "Card", "Wire"],
required: true,
},
orderStatus: [
{
type: {
type: String,
enum: ["Ordered", "Packed", "Shipped", "Delivered"],
default: "Ordered",
},
date: {
type: Date,
},
isCompleted: {
type: Boolean,
default: false,
},
},
],
},
{ timestamps: true }
);
module.exports = mongoose.model("Order", orderSchema);
Address Model:
const mongoose = require("mongoose");
const addressSchema = new mongoose.Schema({
name: {
type: String,
required: true,
trim: true,
min: 10,
max: 60,
},
mobileNumber: {
type: String,
required: true,
trim: true,
},
pinCode: {
type: String,
required: true,
trim: true,
},
locality: {
type: String,
required: true,
trim: true,
min: 10,
max: 100,
},
address: {
type: String,
required: true,
trim: true,
min: 10,
max: 100,
},
cityDistrictTown: {
type: String,
required: true,
trim: true,
},
state: {
type: String,
required: true,
required: true,
},
landmark: {
type: String,
min: 10,
max: 100,
},
alternatePhone: {
type: String,
},
addressType: {
type: String,
required: true,
enum: ["home", "work"],
required: true,
},
});
const userAddressSchema = new mongoose.Schema(
{
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: "User",
},
address: [addressSchema],
},
{ timestamps: true }
);
mongoose.model("Address", addressSchema);
module.exports = mongoose.model("UserAddress", userAddressSchema);
Code that runs the query:
const Order = require("../models/order");
const Cart = require("../models/cart");
const Address = require("../models/address");
const Product = require("../models/product");
exports.getOrders = (req, res) => {
Order.find({ user: req.user._id })
.select("_id paymentStatus paymentType orderStatus items addressId")
.populate("items.productId", "_id name productImages")
.populate("addressId")
.exec((error, orders) => {
if (error) {console.log(error)
return res.status(400).json({ error });}
if (orders) {
res.status(200).json({ orders });
}
});
};

I can't figure out how to populate dynamic reference in mongoose

This is my user model code. I am referencing the favorites using dynamic referencing as there are three types of posts that can be added to favorites
import mongoose from 'mongoose'
import bcrypt from 'bcryptjs'
const userSchema = mongoose.Schema(
{
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
isAdmin: {
type: Boolean,
required: true,
default: false,
},
contact:{
type:Number,
required: true,
unique:true
},
cnic: {
type: Number,
required: true,
unique: true
},
favorites: [
{
postType: {
type: String
},
postId: {
type: mongoose.Schema.Types.ObjectId,
refPath: 'postType'
},
}
],
itemsRented: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Rent',
}
],
itemsRentedOut: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'Rent',
}
],
collectionRequestsSent: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'CommunityService',
}
],
itemsCollected: [
{
type: mongoose.Schema.Types.ObjectId,
ref: 'CommunityService',
}
],
servicesOrdered: [
{
type:mongoose.Schema.Types.ObjectId,
ref: 'Services'
}
],
paymentDetails: {
card: { type: Number },
cvc: { type: Number },
name: { type: String },
email: {type: String },
expiryDate: {
month: { type: Number },
year: { type: Number }
},
},
address: { type: String },
isDisputeResolutionStaff: {
type: String,
default: false
}
},
{
timestamps: true,
}
)
userSchema.methods.matchPassword = async function (enteredPassword) {
return await bcrypt.compare(enteredPassword, this.password)
}
userSchema.pre('save', async function (next) {
if (!this.isModified('password')) {
next()
}
const salt = await bcrypt.genSalt(10)
this.password = await bcrypt.hash(this.password, salt)
})
const User = mongoose.model('User', userSchema)
export default User
This is my controller. I want to get the posts' details added to favorites by using populate but when I run the code it returns the user object not the post details
const getFavorites = asyncHandler(async(req,res) => {
await User.
findById("61b51adfb7b8a64fd87420d3").
populate("favorites").
exec(function (err, story) {
if (err) throw new Error(err);
console.log(story);
});
})

Mongoose adding values to an array

How can I add a User to the School's admins field?
School Schema:
const School = new Schema({
name: { type: String, required: true },
grades_primary: [{ type: Schema.Types.ObjectId, ref: 'Grade' }],
grades_secondary: [{ type: Schema.Types.ObjectId, ref: 'Grade' }],
admins: [{ type: Schema.Types.ObjectId, ref: 'User' }]
})
User Schema
const User = new Schema({
complete_name: { type: String, required: true, },
password: { type: String, required: true },
nombre_de_usuario: { type: String, unique: true, required: true },
email: { type: String, unique: true, required: true },
})
I tried this but it didn't work:
const saved_user = await user.save()
created_school.admins.push(saved_user)
await created_school.save()
use $push
const saved_user = await user.save()
try {
const created_school= await School.findOneAndUpdate({ _id: '1' }, { $push: { admins: saved_user } })
// ....
} catch (error) {
console.log(error);
}

What is the best way to attach properties to mongoose documents

I have an array of posts and each post contains an author id. I want to loop through each post and find author from User model by using author id and then attach it to post. What is the best and efficient way to do it. I am currently doing it this way, but it decreases the performance. Thanks.
posts = await Promise.all(
posts.map(async post => {
post.author = await User.findById(post.author).lean();
return post;
})
);
// POST SCHEMA
const postSchema = new mongoose.Schema({
author: {
type: String,
required: true
},
body: {
type: String,
required: true
},
post_image: {
url: String,
public_id: String,
width: Number,
height: Number
},
date_created: {
type: Date,
default: Date.now()
}
});
// USER SCHEMA
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
register_date: {
type: Date,
required: true,
default: Date.now()
},
friends: {
type: Array,
default: []
}
});
// NEW POST SCHEMA
const postSchema = new mongoose.Schema({
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'users',
required: true
},
body: {
type: String,
required: true
},
post_image: {
url: String,
public_id: String,
width: Number,
height: Number
},
date_created: {
type: Date,
default: Date.now()
}
});
// USER SCHEMA
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
},
register_date: {
type: Date,
required: true,
default: Date.now()
},
friends: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'users',
required: true
}],
});
You can use auto population of mongo object in mongoose. It won't cause performance issues as it uses id index. Similar to this doc: https://mongoosejs.com/docs/populate.html
Your query will look like this:
const post = await Post.find({ author: { $in: req.user.friends }})
.populate('author')
.exec();
console.log(post);
Or you can use aggregate according to this document: https://mongoosejs.com/docs/api/aggregate.html
Your query will then look like:
const query = [
{ $match: { author: { $in: req.user.friends } } },
{ $lookup: { from: "users", localField: "author", foreignField: "_id", as: "authorDetails" } },
{ $unwind: "authorDetails" },
]
const post = await Post.aggregate(query).exec();
console.log(post);

Categories

Resources