Related
So in my project i have two different models . Tour Model and Review Model. Review Model has parent reference of tour id. I want to add virtual populate on tour model so that I can get all reviews related to the tour. Basically doing it other way round.
So what I am expecting here is that whenever I hit a route on getTour I should see a property called "reviews" added to the response object but there is actually isn't. Please tell me is there anything I'm missing here.
const mongoose = require('mongoose');
const slugify = require('slugify');
const User = require('./userModel');
const Review = require('./reviewModel');
const tourSchema = new mongoose.Schema(
{
name: {
type: String,
required: [true, 'A tour must have a name'],
unique: true,
maxlength: [40, 'A tour namme must have less or equal 40 characters'],
minlength: [10, 'A tour namme must have greater or equal 10 characters'],
},
slug: String,
duration: {
type: Number,
required: [true, 'A tour must have a duration'],
},
maxGroupSize: {
type: Number,
required: [true, 'A tour must have a GroupSize'],
},
difficulty: {
type: String,
required: [true, 'A tour must have difficulty'],
},
ratingsQuantity: {
type: Number,
default: 0,
},
ratingsAverage: {
type: Number,
default: 4.5,
min: [1, 'Rating must be above 1.0'],
max: [5, 'Rating must be below 5.0'],
},
price: {
type: Number,
required: [true, 'A tour must have a price '],
},
priceDiscount: {
type: Number,
validate: {
validator: function (val) {
return val < this.price;
},
message: 'Discount must be lower than the price',
},
},
summary: {
type: String,
trim: true,
required: [true, 'A tour must have summary'],
},
description: {
type: String,
trim: true,
},
imageCover: {
type: String,
required: [true, 'A tour must have a cover image'],
},
images: [String],
createdAt: {
type: Date,
default: Date.now(),
},
startDates: [Date],
secretTour: {
type: Boolean,
dafault: false,
},
startLocation: {
//Geo json
type: {
type: String,
default: 'Point',
enum: ['Point'],
},
coordinates: [Number],
address: String,
description: String,
},
locations: [
{
type: {
type: String,
default: 'Point',
enum: ['Point'],
},
coordinates: [Number],
address: String,
description: String,
day: Number,
},
],
guides: [
{
type: mongoose.Schema.ObjectId,
ref: 'User',
},
],
},
{
toJSON: { virtuals: true },
toObject: { virtuals: true },
}
);
tourSchema.virtual('reviews', {
ref: 'Review', //name of model
foreignField: 'tour', //foreign property in review model
localField: '_id',
});
const Tour = mongoose.model('Tour', tourSchema);
module.exports = Tour;
const mongoose = require('mongoose');
const slugify = require('slugify');
const reviewSchema = new mongoose.Schema(
{
review: {
type: String,
required: true,
},
rating: {
type: Number,
min: 1,
max: 5,
required: true,
},
createdAt: {
type: Date,
default: Date.now,
},
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: [true, 'Review must belong to a user'],
},
tour: {
type: mongoose.Schema.ObjectId,
ref: 'Tour',
required: [true, 'Review must belong to a tour'],
},
},
{
toJSON: { virtuals: true },
toObject: { virtuals: true },
}
);
reviewSchema.pre(/^find/, function (next) {
this.populate({
path: 'user',
select: 'name',
}).populate({
path: 'tour',
select: 'name',
});
next();
});
const Review = mongoose.model('Review', reviewSchema);
module.exports = Review;
You just have to populate reviews field. so after doing virtual property write this code below it in file contains tourSchema.
If you want to find single tour
tourSchema.pre('findOne', function (next) {
this.populate('reviews');
next();
});
I'm unable to get my data to go into my MongoDB collection. It gives me this message:
Here's the Schema. I'm able to make GET, PATCH, AND DELETE work but not POST. I've tried looking up the answers in regards to this issue, however, the support doesn't look stellar. I
const IssueSchema = new mongoose.Schema({
projectTitle: {
type: String,
required: [true, 'must provide project title'],
trim: true,
maxLength: [30, 'project name cannot be more than 30 characters']
},
completed: {
type: Boolean,
default: false
},
description: {
type: String,
required: [true, 'must provide a succinct description of the project'],
trim: true,
maxLength: [120, 'project description cannot be more than 120 characters']
},
createdAt: {
type: Date,
default: Date.now()
},
issueTitle: {
type: String,
required: [true, 'must provide issue title'],
trim: true,
maxLength: [30, 'project name cannot be more than 30 characters']
},
priority: {
type: String,
enum: {
values: ['low', 'normal', 'important', 'critical'],
message: `{VALUE} is not supported`
}
},
issuer: {
type: String,
enum: {
values: ['Admin', 'Lead', 'QA'],
message: `{VALUE} is not supported`
}
},
developer: {
type: String,
enum: {
values: ['Jason W.', 'Ada L.', 'Alan T.'],
message: `{VALUE} is not supported`
}
},
status: {
type: String,
enum: {
values: ['open', 'closed'],
message: `{VALUE} is not supported`
}
},
type: {
type: String,
trim: true
}
})
module.exports = mongoose.model('Issue', IssueSchema)```
I have a product schema in which user(who uploaded ,created the product) is there who creates a product and then there is an order , order schema has the product included , I want it to include the products uploader user . Can anyone help me to do that ? I really hope i make it clear enough it's haunting me for days and I have searched the internet
const mongoose = require('mongoose')
const orderSchema = mongoose.Schema({
shippingInfo: {
address: {
type: String,
required: true
},
city: {
type: String,
required: true
},
phoneNo: {
type: String,
required: true
},
postalCode: {
type: String,
required: true
},
country: {
type: String,
required: true
}
},
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},
orderItems: [
{
name: {
type: String,
required: true
},
quantity: {
type: Number,
required: true
},
image: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
product: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Product'
},
}
],
paymentInfo: {
id: {
type: String
},
status: {
type: String
}
},
paidAt: {
type: Date
},
itemsPrice: {
type: Number,
required: true,
default: 0.0
},
taxPrice: {
type: Number,
required: true,
default: 0.0
},
shippingPrice: {
type: Number,
required: true,
default: 0.0
},
totalPrice: {
type: Number,
required: true,
default: 0.0
},
orderStatus: {
type: String,
required: true,
default: 'Processing'
},
deliveredAt: {
type: Date
},
createdAt: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Order', orderSchema)
this is my product Schema
const mongoose = require('mongoose')
const productSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'Please enter product name'],
trim: true,
maxLength: [100, 'Product name cannot exceed 100 characters']
},
price: {
type: Number,
required: [true, 'Please enter product price'],
maxLength: [5, 'Product name cannot exceed 5 characters'],
default: 0.0
},
description: {
type: String,
required: [true, 'Please enter product description'],
},
ratings: {
type: Number,
default: 0
},
images: [
{
public_id: {
type: String,
required: true
},
url: {
type: String,
required: true
},
}
],
category: {
type: String,
required: [true, 'Please select category for this product'],
enum: {
values: [
'Electronics',
'Cameras',
'Laptops',
'Accessories',
'Headphones',
'Food',
"Books",
'Clothes/Shoes',
'Beauty/Health',
'Sports',
'Outdoor',
'Home'
],
message: 'Please select correct category for product'
}
},
seller: {
type: String,
required: [true, 'Please enter product seller']
},
stock: {
type: Number,
required: [true, 'Please enter product stock'],
maxLength: [5, 'Product name cannot exceed 5 characters'],
default: 0
},
numOfReviews: {
type: Number,
default: 0
},
reviews: [
{
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true
},
name: {
type: String,
required: true
},
rating: {
type: Number,
required: true
},
comment: {
type: String,
required: true
}
}
],
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true
},
createdAt: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Product', productSchema);
this is my user Schema
const mongoose = require('mongoose');
const validator = require('validator');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken')
const crypto = require('crypto')
const userSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'Please enter your name'],
maxLength: [30, 'Your name cannot exceed 30 characters']
},
email: {
type: String,
required: [true, 'Please enter your email'],
unique: true,
validate: [validator.isEmail, 'Please enter valid email address']
},
password: {
type: String,
required: [true, 'Please enter your password'],
minlength: [6, 'Your password must be longer than 6 characters'],
select: false
},
avatar: {
public_id: {
type: String,
required: true
},
url: {
type: String,
required: true
}
},
role: {
type: String,
default: 'user'
},
createdAt: {
type: Date,
default: Date.now
},
resetPasswordToken: String,
resetPasswordExpire: Date
})
// Encrypting password before saving user
userSchema.pre('save', async function (next) {
if (!this.isModified('password')) {
next()
}
this.password = await bcrypt.hash(this.password, 10)
})
// Compare user password
userSchema.methods.comparePassword = async function (enteredPassword) {
return await bcrypt.compare(enteredPassword, this.password)
}
// Return JWT token
userSchema.methods.getJwtToken = function () {
return jwt.sign({ id: this._id }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_TIME
});
}
// Generate password reset token
userSchema.methods.getResetPasswordToken = function () {
// Generate token
const resetToken = crypto.randomBytes(20).toString('hex');
// Hash and set to resetPasswordToken
this.resetPasswordToken = crypto.createHash('sha256').update(resetToken).digest('hex')
// Set token expire time
this.resetPasswordExpire = Date.now() + 30 * 60 * 1000
return resetToken
}
module.exports = mongoose.model('User', userSchema);
Order.find(any order).populate([ { path: 'orderItems.product', model: 'Order', populate: [ { path: 'user', model: 'User', select: 'name', }, ], }, ]) ` Note: you can edit it for correct paths
This is my order Schema
the person who actually starts the order , can get his SPECIFIC ORDERS, but the person who gets order to his product can not get specific orders.Which are his , i am copying a tutorial and making a product please help with that
const mongoose = require('mongoose')
const orderSchema = mongoose.Schema({
shippingInfo: {
address: {
type: String,
required: true
},
city: {
type: String,
required: true
},
phoneNo: {
type: String,
required: true
},
postalCode: {
type: String,
required: true
},
country: {
type: String,
required: true
}
},
user: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'User'
},
orderItems: [
{
name: {
type: String,
required: true
},
quantity: {
type: Number,
required: true
},
image: {
type: String,
required: true
},
price: {
type: Number,
required: true
},
product: {
type: mongoose.Schema.Types.ObjectId,
required: true,
ref: 'Product'
}
}
],
paymentInfo: {
id: {
type: String
},
status: {
type: String
}
},
paidAt: {
type: Date
},
itemsPrice: {
type: Number,
required: true,
default: 0.0
},
taxPrice: {
type: Number,
required: true,
default: 0.0
},
shippingPrice: {
type: Number,
required: true,
default: 0.0
},
totalPrice: {
type: Number,
required: true,
default: 0.0
},
orderStatus: {
type: String,
required: true,
default: 'Processing'
},
deliveredAt: {
type: Date
},
createdAt: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Order', orderSchema)
this is my product schema
const mongoose = require('mongoose')
const productSchema = new mongoose.Schema({
name: {
type: String,
required: [true, 'Please enter product name'],
trim: true,
maxLength: [100, 'Product name cannot exceed 100 characters']
},
price: {
type: Number,
required: [true, 'Please enter product price'],
maxLength: [5, 'Product name cannot exceed 5 characters'],
default: 0.0
},
description: {
type: String,
required: [true, 'Please enter product description'],
},
ratings: {
type: Number,
default: 0
},
images: [
{
public_id: {
type: String,
required: true
},
url: {
type: String,
required: true
},
}
],
category: {
type: String,
required: [true, 'Please select category for this product'],
enum: {
values: [
'Electronics',
'Cameras',
'Laptops',
'Accessories',
'Headphones',
'Food',
"Books",
'Clothes/Shoes',
'Beauty/Health',
'Sports',
'Outdoor',
'Home'
],
message: 'Please select correct category for product'
}
},
seller: {
type: String,
required: [true, 'Please enter product seller']
},
stock: {
type: Number,
required: [true, 'Please enter product stock'],
maxLength: [5, 'Product name cannot exceed 5 characters'],
default: 0
},
numOfReviews: {
type: Number,
default: 0
},
reviews: [
{
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true
},
name: {
type: String,
required: true
},
rating: {
type: Number,
required: true
},
comment: {
type: String,
required: true
}
}
],
user: {
type: mongoose.Schema.ObjectId,
ref: 'User',
required: true
},
createdAt: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Product', productSchema);
these are my order controller function
exports.myOrders = catchAsyncErrors(async (req, res, next) => {
const orders = await Order.find({ user: req.user.id })
res.status(200).json({
success: true,
orders
})
})
// Get all orders - ADMIN => /api/v1/admin/orders/
exports.allOrders = catchAsyncErrors(async (req, res, next) => {
const orders = await Order.find({ user: req.user.id })
//let totalAmount = 0;
/* orders.forEach(order => {
totalAmount += order.totalPrice
})
*/
res.status(200).json({
success: true,
// totalAmount,
orders
})
})
the user who initiate the order can see the orders which he initiated but the person to which order was given can not get specific order
I hope i make it clear enough , please help me I am a noob
For user you can use Model.find({ user: user_id });
For seller, you should use Model.find({ user: user_id, seller: seller_id })
This will match orders from the USER for the SELLER
I've got a tour collection with the following model:
const tourSchema = new mongoose.Schema(
{
slug: {
type: String,
},
name: {
type: String,
required: ['true', 'a tour must have a name'],
unique: true,
trim: true,
maxlength: [40, 'a tour name must not be more than 40 characters'],
minlength: [10, 'a tour must not be less than 10 characters'],
// validate: [validator.isAlpha, 'name should only contain A-Z'],
},
duration: {
type: Number,
required: [true, 'a tour must have a duration'],
},
maxGroupSize: {
type: Number,
required: [true, 'a tour must have a group size'],
},
difficulty: {
type: String,
required: [true, 'a tour should have a difficulty'],
enum: {
values: ['easy', 'medium', 'difficult'],
message: 'Difficulty is either easy, medium or difficult',
},
},
ratingsAverage: {
type: Number,
default: 4.5,
min: [1, 'Rating must be more than 1'],
max: [5, 'Maximum rating is 5'],
set: (val) => Math.round(val * 10) / 10,
},
ratingsQuantity: {
type: Number,
default: 0,
},
price: {
type: Number,
required: ['true', 'a tour must have a price'],
},
priceDiscount: {
type: Number,
validate: {
validator: function (val) {
// this only points to current doc on NEW document creation
return val < this.price;
},
message: 'Discount price {VALUE} should be lower than regualr price',
},
},
summary: {
type: String,
trim: true,
required: ['true', 'a tour must have a description'],
},
description: {
type: String,
trim: true,
},
imageCover: {
type: String,
required: ['true, a tour must have a cover image'],
},
images: [String],
createdAt: {
type: Date,
default: Date.now(),
select: false,
},
startDates: [Date],
secretTour: {
type: Boolean,
default: false,
},
startLocation: {
// GEOJSON
type: {
type: String,
default: 'Point',
enum: ['Point'],
},
coordinates: [Number],
address: String,
description: String,
},
locations: [
{
type: {
type: String,
default: 'Point',
enum: ['Point'],
},
coordinates: [Number],
address: String,
description: String,
day: Number,
},
],
guides: [{ type: mongoose.Schema.ObjectId, ref: 'User' }],
},
{
toJSON: { virtuals: true },
toObject: { virtuals: true },
}
);
I've written an aggregate of type $GeoNear like this:
const distances = await Tour.aggregate([
{
$geoNear: {
near: {
type: 'Point',
coordinates: [lng * 1, lat * 1],
},
distanceField: 'distance',
distanceMultiplier: multiplier,
},
},
]);
I've read the official documentation, and everything else that I could find online, left no stone upturned.
I'm aware that I should have a '2dSphere' index. And it exists on my mongoDB. I've also made sure that this is the first aggregation in the pipeline.
However the results are always empty! this is so frustrating! could be because of this https://github.com/parse-community/parse-server/pull/6540. Any opinion is much appreciated.