I created an Express.js MongoDB API that filters products based on the filter property, the problem is that I want to make this API output exactly match the filter property. but currently for example if product A has [{name: 'a', value: '1'}, {name: 'b', value: '2'}] and product B has [{name: 'a', value: '1'}, {name: 'c', value: '3'}] and if I pass the data to the API like [{name: 'a', value: '1'}, {name: 'b', value: '2'}], it returns product B too, because it has {name: 'a', value: '1'} as a value inside filter property. How can I make my query exactly match based on passed values?
this is product schema:
const mongoose = require('mongoose');
const { s, rs, rn, rref, ref, b } = require('../utils/mongo');
let schema = new mongoose.Schema(
{
user: rref('user'),
name: rs,
description: s,
images: [s],
price: rn,
categories: ref('category'),
filters: [
{
parent: ref('filter'),
value: s,
name: s,
},
],
subFilter: [
{
parent: s,
value: s,
title: s,
},
],
published: b,
},
{ timestamps: true }
);
module.exports = mongoose.model('product', schema);
and this is my query:
filter: async (req, res) => {
try {
const { categories, filters } = req.body;
let products;
if (filters.length > 0) {
let targ_cat = categories;
let any_one_of = filters;
let or_list = [];
any_one_of.forEach(function (f) {
or_list.push({
$and: [
{ $eq: [f['name'], '$$this.name'] },
{ $eq: [f['value'], '$$this.value'] },
],
});
});
let or_expr = { $or: or_list };
products = await Product.aggregate([
{ $match: { categories: new ObjectId(targ_cat) } },
{
$addFields: {
filters: { $filter: { input: '$filters', cond: or_expr } },
},
},
{
$match: {
$expr: { $gt: [{ $size: '$filters' }, 0] },
},
},
]);
} else {
products = await Product.find({ categories });
}
res.status(200).json(products);
} catch (err) {
console.log(err);
res.status(500).json(err);
}
}
this one is what I want to send as body to the API
{
category: '62445c3d922d127512867245'
filters: [
{ name: 'filter name 1', value: '62445c3d922d127512861236' },
{ name: 'filter name 2', value: '62445c3d922d127512861458' },
.....
]
}```
You can use a simple find for exact match:
db.collection.find({
category: "62445c3d922d127512867245",
filters: [
{
name: "filter name 1",
value: "62445c3d922d127512861236"
},
{
name: "filter name 2",
value: "62445c3d922d127512861458"
}
]
})
See how it works on the playground example