Related
Following is the WorkingDay model
const workingDaySchema = new mongoose.Schema({
date: { type: String, unique: true, required: true },
availableSlots: [
{
startTime: Date,
endTime: Date,
size: Number,
enrolledUsers: [{ type: Schema.Types.ObjectId, ref: 'Response' }]
}
]
})
module.exports = mongoose.model('WorkingDay', workingDaySchema);
And the following is the Response model:
const responseSchema = new Schema(
{
id: { type: String },
name: { type: String, required: true },
age: { type: String },
gender: { type: String },
height: { type: String },
weight: { type: String },
food: { type: String },
phone: { type: String },
email: { type: String },
category: { type: Array },
answers: { type: Object },
assignedSlot: { type: Schema.Types.ObjectId, ref: availableSlots, default: null }
},
{
timestamps: true,
}
);
module.exports = mongoose.model("Response", responseSchema);
Every object inside the availableSlots array has it own unique _id.
How to create a reference to an object inside availableSlots from the assignedSlot field of response? Also how to populate the same?
I tried referencing the availableSlots objects using
assignedSlot: { type: Schema.Types.ObjectId, ref: availableSlots, default: null }
and
assignedSlot: { type: Schema.Types.ObjectId, ref: "WorkingDay.availableSlots", default: null }
but it did not work.
const { ObjectId } = mongoose.Schema.Types;
assignedSlot: [{ type: ObjectId ,ref:"WorkingDay"}]
Given your schema structure, you should reference the WorkingDay collection:
assignedSlot: { type: Schema.Types.ObjectId, ref: 'WorkingDay', default: null }
Then, you can populate the reference with:
const response = await Response.findOne({}).populate('assignedSlot').exec();
if (response && response.assignedSlot) {
console.log(response.assignedSlot.availableSlots);
}
Below is my API for fetching all the orders of a specific restaurant from a mongoDB database.
My search is based on the restaurant id which I am getting from params and passing it to the query object.
query1 is working but query2 does not return my data.
It is returning an empty array. If I pass a simple object in find() then I am getting a response. But when i use a nested object for getting data I get nothing.
exports.getOrders = async (req, res) => {
const restId = req.params.restId;
console.log("restaurant id", restId);
if (!restId) return res.status(404).send("No restaurant ID found in params");
const query1 = {grandTotal: 600};
const query2 = { restaurant: { restaurantId: restId } };
const response = await Orders.find(query2);
console.log("Printing response inside API function", response);
}
Below is my MongoDB Schema of Orders.
const mongoose = require("mongoose");
const orderSchema = mongoose.Schema({
customer: {
name: {
type: String,
required: true,
},
contact: {
type: String,
required: true,
},
customerId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Customer",
required: true,
},
customerAddress: {
type: String,
required: true,
},
},
restaurant: {
restaurantName: {
type: String,
required: true,
},
contact: {
type: String,
required: true,
},
restaurantId: {
type: mongoose.Schema.Types.ObjectId,
ref: "Restaurant",
required: true,
},
},
/*date: {
day: {
type: Number,
required: true,
},
month: {
type: String,
required: true,
},
year: {
type: Number,
required: true,
},
},
type: {
type: String,
enum: ["delivery","takeaway"],
required: true,
},*/
items: [
{
itemId: { type: String, required: true },
itemName: { type: String, required: true },
itemDescription: { type: String, required: true },
price: {type: Number, required: true},
quantity: { type: Number, required: true },
total: {type: Number, required: true},
},
],
grandTotal: {type: Number, required: true},
status: {
type: String,
enum: ["pending", "rejected","cancelled","accepted","received"],
required: true,
},
});
orderSchema.virtual("booking", {
ref: "Booking",
localField: "_id",
foreignField: "orderId",
});
orderSchema.set("toObject", { virtual: true });
orderSchema.set("toJSON", { virtual: true });
const Orders = mongoose.model("Orders", orderSchema);
exports.Orders = Orders;
change query2 to this
const query2 = { "restaurant.restaurantId": restId } };
I have succesfully used population across multiple levels and field selection separately. But I couldn't find a way to do them both at the same time.
Population across multiple levels
Profile.findOne({ user: req.user.id })
.populate({
path: "user",
populate: { path: "following" },
})
Field selection:
Profile.findOne({ user: req.user.id })
.populate("user", ["name", "avatar"])
I want to do something like this:
NOTE: THIS DOESN'T WORK
Profile.findOne({ user: req.user.id })
.populate({
path: ["user", ["name", "avatar"]],
populate: { path: "following" },
This is the Profile model:
const ProfileSchema = new Schema({
//We want to associate the user with the profile
user: {
//This will associate the user by his id
type: Schema.Types.ObjectId,
ref: "users",
},
// We want a user friendly url
handle: {
type: String,
// required: true, // Even though we are doing pre-validatioon
max: 40,
},
bio: {
type: String,
},
school: {
type: String,
},
major: {
type: String,
},
website: {
type: String,
},
location: {
type: String,
},
// Optional (might add it later)
/**
* status: {
//where they are in their career
type: String,
required: true
},
*/
skills: {
// In the form they will put skill1,skill2,.. and we will turn that into an array
type: [String],
// required: true,
},
interests: {
// In the form they will put interest1,interest2,.. and we will turn that into an array
type: [String],
// required: true,
},
help_offers: {
// In the form they will put help_offer1,help_offer2,.. and we will turn that into an array
type: [String],
// required: true,
},
// Might be volunteering experience
experience: [
{
title: { type: String, required: true },
company: {
type: String,
required: true,
},
location: {
type: String,
},
from: {
type: Date,
required: true,
},
to: {
type: Date,
// Not required, going to be a checkbox
},
current: {
type: Boolean,
default: false,
},
description: {
type: String,
},
},
],
education: [
{
school: { type: String, required: true },
degree: {
type: String,
required: true,
},
fieldofstudy: {
type: String,
required: true,
},
from: {
type: Date,
required: true,
},
to: {
type: Date,
// Not required, going to be a checkbox
},
current: {
type: Boolean,
default: false,
},
description: {
type: String,
},
},
],
social: {
youtube: {
type: String,
},
twitter: {
type: String,
},
facebook: {
type: String,
},
linkedin: {
type: String,
},
instagram: {
type: String,
},
},
date: {
type: Date,
dafault: Date.now,
},
videoURL: {
type: String,
},
});
This is the User model:
const UserSchema = new Schema({
name: {
type: String,
required: true,
},
surname: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
avatar: {
type: String,
},
birthday: {
type: String,
required: true,
},
country: {
type: String,
required: true,
},
date: {
type: Date,
default: Date.now,
},
following: [
{
type: Schema.Types.ObjectId,
//The User has only ObjectId in uses array. ref helps us get full fields of User when we call populate() method.
//https://bezkoder.com/mongodb-many-to-many-mongoose/
ref: "users",
},
],
followers: [
{
type: Schema.Types.ObjectId,
ref: "users",
},
],
});
I am not sure if I understood your aim by this
Profile.findOne({ user: req.user.id })
.populate({
path: ["user", ["name", "avatar"]],
populate: { path: "following" },
But if what i understood is what you want, then we're lucky. here is what i got.
await RequestAproves.find()
.populate('user', 'firstName surname email roleId')
.populate({
path: 'request',
populate: [
{ path: 'budgetItem', select: 'code name' },
{ path: 'user', select: 'firstName surname' },
],
}
)
More details will come later, Sorry, I couldnt use your schema description, Incase it doesnt work out, let me know, ill try to use your schema.
I have a collection of jobs in MongoDB and in this collection there is a field in the documents named as appliedUser. I want to update this field when a new user applies for this job.So basically this field stores the id's of all the users who are applying for this job.
I am using findOneAndUpdate() function but not able to do it.
Job.findOneAndUpdate({ _id: req.params.id }, { $set: { appliedUser:
req.user.id } }, function(err, job) {
console.log(job);
})
and here is my Schema:
const jobSchema = new Schema({
date: { type: Date, default: Date() },
expirydate: { type: Date, required: true },
name: { type: String, required: true },
companydetails: { type: String, required: true },
address: { type: String, required: true },
role: { type: String, required: true },
city: { type: String, required: true },
minsalary: { type: Number, required: true },
maxsalary: { type: Number, required: true },
skills: { type: Array, required: true },
minex: { type: Number, required: true },
appliedUser: [{ type: Schema.Types.ObjectId, ref: 'users', unique:
true }],
user: { type: String, required: true }
})
The array of the document is not updating. I am not able to find the errors.
Look like what you need is $addToSet. Example:
Job.findOneAndUpdate({ _id: req.params.id }, { $addToSet: { appliedUser: req.user.id } }, function(err, job) {
console.log(job);
})
My schema is as shown below:
const order = new Schema({
order_status: Number,
foodtruck_id: { type: Schema.Types.ObjectId, ref: 'foodtruck' },
customer_id: { type: Schema.Types.ObjectId, ref: 'user' },
items: [{ type: Schema.Types.ObjectId, ref: 'items' }],
user_type: Boolean,
order_time: Date,
order_rating: { type: Number, default: 5.0 },
order_issue_comments: String,
order_special_instruction: String,
order_total: Number,
order_location: String,
order_coupon_code: String,
payment_id: { type: Schema.Types.ObjectId, ref: 'payment' },
order_meta: { type: Schema.Types.Mixed, ref: 'order_sub_info', default: {} }
}, { versionKey: false }, { minimize: false });
my query is as shown below:
order.find({
'foodtruck_id': foodtruck_id.trim()
}).populate('customer_id', {
'_id': 1,
'user_name': 1,
'email_id': 1,
'ph_no': 1,
'login_type': 1
}).populate('items').
populate('order_meta', 'order_otp').exec((err, orderList) => {
if (err) res.json({
status: '500',
message: err
});
else {
console.log("called");
res.json({
status: '200',
message: 'Order list',
data: orderList
});
}
});
For this query,it is giving me Cast to ObjectId failed for value at path _id as order_meta has default value {}. How to have effective populate query so that It can take care of this testcase?
It is not good idea to put empty object in a place, where reference id is expected. Both - for having problem with populate and for common sense too (if it is field which has reference, it should be null/undefined or reference itself).
It is common that you want to transform your data at some endpoint, but it should not interfere with database or business logic of application.
You can defined toJSON method that should be used for your model. In your case
const order = new Schema({
order_status: Number,
foodtruck_id: { type: Schema.Types.ObjectId, ref: 'foodtruck' },
customer_id: { type: Schema.Types.ObjectId, ref: 'user' },
items: [{ type: Schema.Types.ObjectId, ref: 'items' }],
user_type: Boolean,
order_time: Date,
order_rating: { type: Number, default: 5.0 },
order_issue_comments: String,
order_special_instruction: String,
order_total: Number,
order_location: String,
order_coupon_code: String,
payment_id: { type: Schema.Types.ObjectId, ref: 'payment' },
order_meta: { type: Schema.Types.ObjectId, ref: 'order_sub_info'}
}, { versionKey: false }, { minimize: false });
order.options.toJSON = {
transform(zipRequestDocument, ret, options) { // eslint-disable-line no-unused-vars
if (!ret.order_meta){
ret.order_meta = {};
}
},
};