I’m working with Express.js to build a MongoDB API that filters products by specific criteria. I need the API to return products precisely matching the provided filter attributes. Currently, if product A has [{name: 'a', value: '1'}, {name: 'b', value: '2'}]
and product B has [{name: 'a', value: '1'}, {name: 'c', value: '3'}]
, passing the filter [{name: 'a', value: '1'}, {name: 'b', value: '2'}]
incorrectly returns product B as well. How can I enforce exact filter matches?
My product schema is as follows:
const mongoose = require('mongoose');
const { str, requiredStr, number, refObj } = require('../utils/mongo');
let schema = new mongoose.Schema({
owner: refObj('user'),
title: requiredStr,
description: str,
images: [str],
cost: number,
category: refObj('category'),
criteria: [{
parent: refObj('filter'),
term: str,
label: str,
}],
subCriteria: [{
parent: str,
term: str,
header: str,
}],
available: Boolean,
}, { timestamps: true });
module.exports = mongoose.model('product', schema);
Here’s my query logic:
filter: async (req, res) => {
try {
const { categories, criteria } = req.body;
let products;
if (criteria.length > 0) {
let targetedCat = categories;
let eachFilter = criteria;
let conditions = [];
eachFilter.forEach(function (filter) {
conditions.push({
$and: [
{ $eq: [filter['name'], '$$this.name'] },
{ $eq: [filter['value'], '$$this.value'] },
],
});
});
let combinedConditions = { $or: conditions };
products = await Product.aggregate([
{ $match: { categories: new ObjectId(targetedCat) } },
{
$addFields: {
criteria: { $filter: { input: '$criteria', cond: combinedConditions } },
},
},
{
$match: {
$expr: { $gt: [{ $size: '$criteria' }, 0] },
},
},
]);
} else {
products = await Product.find({ categories });
}
res.status(200).json(products);
} catch (error) {
console.error(error);
res.status(500).json(error);
}
}
The body I intend to send is:
{
"category": "62445c3d922d127512867245",
"filters": [
{ "name": "filter name 1", "value": "62445c3d922d127512861236" },
{ "name": "filter name 2", "value": "62445c3d922d127512861458" }
]
}