Reputation: 15
Please help. Still relatively new with Nodejs and Angular. I have the below backend code on Nodejs and I am not able to filter the data by country from MongoDB through req.query.countries I can't for the life of me understand what is wrong here. Thanks in advance for any clues, pointers or solution.
My backend code is as follows tourController.js file
exports.getToursByCountry = catchAsync(async (req, res, next) => {
let filter = {};
if (req.query.countries) {
console.log(req.query.countries);
filter = { country: req.query.countries.split(',') };
}
console.log(filter);
const tourList = await Tour.find(filter).populate('country');
console.log(tourList);
if (!tourList) {
next(new AppError('Sorry could not retrieve tours by country', 400));
}
res.status(200).json({
status: 'success',
results: tourList.length,
data: {
data: tourList
}
});
});
tourModel.js file
const mongoose = require('mongoose');
const slugify = require('slugify');
// const User = require('./userModel');
const tourSchema = new mongoose.Schema(
{
name: {
type: String,
required: [true, 'A tour must have a name'],
unique: true,
trim: true,
maxlength: [
120,
'The tour name must have less or equal than 120 characters'
],
minlength: [
10,
'The tour name must have more or equal than 10 characters'
]
},
slug: String,
country: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Country'
},
duration: {
type: Number,
required: [true, 'A tour must have a duration'],
validate: {
validator: val => {
//'this' only works for the new posting of tour and not on update
return val < 22;
},
message: 'The duration {VALUE} days should be below the 22 days'
}
},
maxGroupPair: {
type: Number,
required: [true, 'A tour must have a maximum group pair size']
},
singleSupplement: {
type: Number,
required: [true, 'A tour must have a single supplment specified']
},
difficulty: {
type: String,
required: [true, 'A tour must have a difficulty'],
enum: {
values: ['easy', 'medium', 'difficult'],
message: 'Difficulty is either: easy, medium nor difficult'
},
match: [
new RegExp(/^[a-zA-Z\s]+$/),
'{VALUE} is not valid. Please use only letters'
]
},
ratingsAverage: {
type: Number,
min: [1, 'Rating must be above 1.0'],
max: [5, 'Rating must be below 5.0'],
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 works for the new posting of tour and not on update
return val < this.price;
},
message: 'Discount price {VALUE} should be below the regular price'
}
},
overview: {
type: String,
trim: true,
required: [true, 'A tour must have an overview']
},
imageCover: {
type: String,
required: [true, 'A tour must have a cover image']
},
images: [String],
minimumAge: {
type: String,
required: [true, 'A tour must have a minimum age'],
maxlength: [
10,
'The minimum age must have less or equal than 10 characters'
]
},
dateCreated: {
type: Date,
default: Date.now
},
availabilityDates: [String],
isFeatured: {
type: Boolean,
default: false
},
secretTour: {
type: Boolean,
default: false
},
departureLocation: {
// GeoJSON
type: {
type: String,
default: 'Point',
enum: ['Point']
},
coordinates: [Number],
town: String,
decription1: String,
decription2: String
},
locations: [
{
type: {
type: String,
default: 'Point',
enum: ['Point']
},
Area: String,
coordinates: [Number],
image: String,
overnight: String,
Meals: String,
description: String,
day: [Number]
}
],
guides: [
{
type: mongoose.Schema.ObjectId,
ref: 'User'
}
]
},
{
toJSON: { virtuals: true },
toObject: { virtuals: true }
}
);
// tourSchema.index({ price: 1 });
tourSchema.index({ price: 1, ratingsAverage: -1 });
tourSchema.index({ slug: 1 });
tourSchema.index({ departureLocation: '2dsphere' });
tourSchema.virtual('id').get(function() {
return this._id.toHexString();
});
tourSchema.set('toJSON', {
virtuals: true
});
tourSchema.virtual('durationWeek').get(function() {
return this.duration / 7;
});
// Virtual populate - this approach does not persist the infomation to the database
tourSchema.virtual('reviews', {
ref: 'Review',
foreignField: 'tour',
localField: '_id'
});
//DOCUMENT MIDDLEWARE: runs before .save() and .create() & not on .insertMany
tourSchema.pre('save', function(next) {
this.slug = slugify(this.name, { lower: true });
next();
});
//QUERY MIDDLEWARE
tourSchema.pre(/^find/, function(next) {
this.find({ secretTour: { $ne: true } });
this.start = Date.now();
next();
});
tourSchema.pre(/^find/, function(next) {
//This will work on find method available in mongoose. 'this' calls populate on the current query
this.populate({
path: 'guides',
select: '-__v -email -phone -street -apartment -suburb -zipCode -code -city'
});
this.populate({
path: 'country',
select: '-__v'
});
next();
});
tourSchema.post(/^find/, function(docs, next) {
console.log(`Query took ${Date.now() - this.start} milliseconds`);
// console.log(docs);
next();
});
//AGGREGATION MIDDLEWARE
tourSchema.pre('aggregate', function(next) {
if (!(this.pipeline().length > 0 && '$geoNear' in this.pipeline()[0])) {
this.pipeline().unshift({
$match: { secretTour: { $ne: true } }
});
}
console.log(this.pipeline());
next();
});
const Tour = mongoose.model('Tour', tourSchema);
module.exports = Tour;
tourRoutes.js route file
router.route('/').get(tourController.getToursByCountry);
Upvotes: 0
Views: 114
Reputation: 15
I have resolved this. My seed json data imported into MongoDB under the field of country was a string in my database instead of an ObjectId.
Upvotes: 1