I’m working on implementing a GET request in my Node.js application, where I need to retrieve data based on various filters provided in the request query. However, I’m facing issues with filtering documents by nested fields in MongoDB using Mongoose.
Here’s how my project model looks:
const projectAddressSchema = new mongoose.Schema(
{
street: {
type: String,
required: true,
},
city: {
type: String,
required: true,
},
postalCode: {
type: String,
required: true,
},
country: {
type: String,
required: true,
},
},
{ _id: false }
);
const priceSchema = new mongoose.Schema(
{
layout: {
type: String,
required: true,
enum: ["studio", "1kk", "2kk", "3kk", "4kk", "5kk"],
},
amount: {
type: Number,
required: true,
},
currency: {
type: String,
required: true,
},
size: {
type: Number,
required: true,
},
},
{ _id: false }
);
const projectSchema = new mongoose.Schema({
projectName: {
type: String,
required: true,
},
price: [priceSchema],
projectLink: {
type: String,
},
projectDescription: {
type: String,
},
projectImages: [String],
projectAddress: projectAddressSchema,
});
const Project = mongoose.model("Project", projectSchema);
And here’s my GET controller:
exports.getAllProjects = async (req, res, next) => {
try {
console.log(req.query);
const features = new APIFeatures(Project.find(), req.query)
.filter()
.sort()
.paginate()
.limitFields();
const projects = await features.query;
res.status(200).json({
status: "success",
results: projects.length,
projects,
});
} catch (err) {
return next(new ServerError(err));
}
};
My APIFeatures class handles filtering, sorting, pagination, and field limiting.
class APIFeatures {
constructor(query, queryString) {
this.query = query;
this.queryString = queryString;
}
filter() {
const queryObj = { ...this.queryString };
const excludedFields = ["page", "sort", "limit", "fields"];
excludedFields.forEach((el) => delete queryObj[el]);
let queryStr = JSON.stringify(queryObj);
queryStr = queryStr.replace(/b(gte|gt|lte|lt)b/g, (match) => `$${match}`);
for (const key in queryObj) {
if (key.includes(".")) {
const [outerKey, innerKey] = key.split(".");
queryObj[outerKey] = {
...queryObj[outerKey],
[innerKey]: queryObj[key],
};
delete queryObj[key];
}
}
this.query = this.query.find(queryObj);
return this;
}
sort() {
if (this.queryString.sort) {
const sortBy = this.queryString.sort.split(",").join(" ");
this.query = this.query.sort(sortBy);
} else {
this.query = this.query.sort("-createdAt");
}
return this;
}
limitFields() {
if (this.queryString.fields) {
const fields = this.queryString.fields.split(",").join(" ");
this.query = this.query.select(fields);
} else {
this.query = this.query.select("-__v");
}
return this;
}
paginate() {
const page = this.queryString.page * 1 || 1;
const limit = this.queryString.limit * 1 || 100;
const skip = (page - 1) * limit;
this.query = this.query.skip(skip).limit(limit);
return this;
}
}
module.exports = APIFeatures;
However, when I make a request like /projects?price.layout=studio, I expect to receive only projects with studio type apartments. Instead, I’m getting all projects from the database.
{
"status": "success",
"results": 2,
"projects": [
{
"_id": "665493755fbd1773ab3f30bf",
"projectName": "Project 1",
"price": [
{
"layout": "studio",
"amount": 6000000,
"currency": "CZK",
"size": 30
},
{
"layout": "1kk",
"amount": 8000000,
"currency": "CZK",
"size": 50
}
],
"projectLink": "https://projectlink.com",
"projectDescription": "Project description",
"projectImages": [
"image1.jpg",
"image2.jpg"
],
"projectAddress": {
"street": "456 Project St",
"city": "Project City",
"postalCode": "67890",
"country": "Project Country"
}
},
{
"_id": "6654939f5fbd1773ab3f30c4",
"projectName": "Project 2",
"price": [
{
"layout": "studio",
"amount": 5000000,
"currency": "CZK",
"size": 30
},
{
"layout": "1kk",
"amount": 9000000,
"currency": "CZK",
"size": 50
}
],
"projectLink": "https://projectlink.com",
"projectDescription": "Project description",
"projectImages": [
"image1.jpg",
"image2.jpg"
],
"projectAddress": {
"street": "456 Project St",
"city": "Project City",
"postalCode": "67890",
"country": "Project Country"
}
}
]
}
Can someone please guide me on how to correctly implement filtering for nested fields in MongoDB using Mongoose?
I tried to googling the problem and i tried to use aggregation, but it didnt help
Danis Bikmeev is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.