$Geonear does not work in the aggregation pipeline - node.js

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.

Related

Mongoose not adding virtual property in the response object using virtual populate

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();
});

Mongoosejs Validation Errors

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)```

getting a mongoose error while connecting this to controller

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 Exeed 100 Characters']
},
price: {
type: Number,
required: [true,'Please Enter Product Price'],
maxLength: [5, 'Product Price Cannot Exeed 5 Characters']
},
description: {
type: String,
required: [true,'Please Enter Product Description'],
},
ratings: {
type: Number,
default: 0
},
images: [
{
public_id: {
type:String,
required: true
},
url:{
typr:String,
required: true
}
}
],
category: {
typr: String,
required: [true, 'Please select category for this Product'],
enum: {
values: [
'Electronics',
'Camera',
'Laptop',
'Accessories',
'HeadPhones',
'Food',
'Books',
'Clothes/Shoes',
'Beauty/Health',
'Sports',
'Outdoor',
'Home'
],
required: [true, 'Please Select correct category for product']
}
},
seller: {
type: String,
required: [true, 'Please enter product seller']
},
stock: {
type: Number,
required: [true, 'Please enter Product stock number'],
maxlength:[5, 'Product name connot exceed 5 characters'],
default: 0
},
numOfReviews: {
type: Number,
default: 0
},
reviews:[
{
name: {
type: String,
required: true
},
rating: {
type: Number,
required: true
},
comment: {
type: String,
required: true
}
}
],
createdAt: {
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('Product',productSchema);
can you check type spelling in your code. You used typr instead of type
So, it is throwing TypeError: Invalid schema configuration: True is not a valid type at path url.required.
One of those line are:
url:{
typr:String,
required: true
}
You have to use the line as:
url:{
type:String,
required: true
}
Make sure spelling mistakes.

Model.find is not a function mongoose

I have a mini casino game and have a mongoose model defined as following:
const jackpotSchema = mongoose.Schema({
round_id: {
type: String,
default: uniqid(),
required: true,
},
createdAt: {
type: Date,
required: true,
default: Date.now
},
closedAt: {
type: Date,
},
startedAt: {
type: Number,
},
roundSecret: {
type: String,
required: true,
},
random_org_hash: {
type: String,
},
random_org_obj: {
type: String
},
roundSecretHash: {
type: String,
},
winningPercentage: {
type: Number,
// required: true,
// first 5 characters of the secret hash, converted into decimal then divided by 10K
},
publicHash: {
type: String,
required: true,
// SHA-256 roundSecret + winningPercentage
},
finalHash: {
type: String,
},
winningTicket: {
type: Number,
},
winningDepositIndex: {
type: Number,
},
deposits: [{
uid: {
type: String,
required: true,
},
user: {
type: String,
required: true,
},
nonce: {
type: Number,
},
amount: {
type: Number,
required: true,
},
user_avatar: {
type: String,
},
ticketRangeMin: {
type: Number,
required: true,
},
ticketRangeMax: {
type: Number,
required: true,
},
referral: {type: String},
timestamp: {type: Date},
timestamp_readable: {type: String}
}],
total: {
type: Number,
required: true,
default: 0,
},
totalTickets: {
type: Number,
default: 0,
},
winner: {
type: String,
default: "",
},
winner_avatar: {
type: String,
},
active: {
type: Boolean,
default: true,
required: true,
},
open: {
type: Boolean,
required: true,
default: true,
},
roundTime: {
type: Number,
// default: potConfig.potLength,
default: 20000,
},
success: {
type: Boolean,
},
fee: {
type: Number,
default: potConfig.potFee,
}
})
module.exports = mongoose.model("Jackpot", jackpotSchema)
When running my app locally, I experience no errors.
However when running on a ubuntu production environment, I get the following error:
Jackpot.find is not a function
The stack trace says that the error is coming from db_utils.js
which looks like the following:
const Jackpot = require("./models/Jackpot");
...
async retrieveStats () {
var jackpots = await Jackpot.find().lean();
}
I have checked to see whether my module.exports was defined correctly, and it is. Not sure why this error is happening.
My local and production node versions match.
12.18.4
Don't you need to do
const jackpotSchema = new mongoose.Schema({...})
instead of
const jackpotSchema = mongoose.Schema({...})

want to show orders only to specific product owners to which orders has been given in mongodb MERN STACK DEVELOPMENT

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

Resources