I want to create a dynamic MongoDB query on the basis of input variables I try to put query as a string but it's not working.
let carsPromise = Car.find({
carsFetchQuery(company, model, minPrice, maxPrice),
})
.skip(offSet)
.limit(rowsPerPage)
.lean();
Function to create fetch query dynamically if input parameters are not null
const createCarFetchquery = (company, model, minPrice, maxPrice) => {
if (
company === null &&
model === null &&
minPrice === null &&
maxPrice === null
)
return '';
let query = `$and: [
{
$or: [{
${getQuery('$eq', 'company', company)} ${model ? ',' : ''}
${getQuery('$eq', 'model', model)} ${minPrice ? ',' : ''}
${getQuery('$gte', 'minPrice', minPrice)} ${maxPrice ? ',' : ''}
${getQuery('$eq', 'maxPrice', maxPrice)}
}],
},
]
`;
Helper function to get query expression
const getQuery = (opertor, key, value) => {
if (value) {
return `${key}: {${opertor}: '${value}'}`;
}
return '';
};
But it is not working any help
CodePudding user response:
You can not inject string in to query, but you can pass an object in query, prepare an array of objects and use it in query,
For understanding i have updated your method as below, you can change it as per your requirement,
const createCarFetchquery = (company, model, minPrice, maxPrice) => {
let query = [];
if (company) query.push(getQuery('$eq', 'company', company));
if (model) query.push(getQuery('$eq', 'model', model));
if (minPrice) query.push(getQuery('$gte', 'minPrice', minPrice));
if (maxPrice) query.push(getQuery('$eq', 'maxPrice', maxPrice));
if (query.length) return { $or: query };
return {};
}
const getQuery = (opertor, key, value) => {
return { [key]: { [opertor]: value } };
};
console.log(createCarFetchquery("ABC", "A", 10, 12));
and use it in your query, but make sure you have wrapped your query by async/await method,
let carsPromise = await Car.find(
carsFetchQuery(company, model, minPrice, maxPrice)
)
.skip(offSet)
.limit(rowsPerPage)
.lean();
CodePudding user response:
find requires a JSON object, thus it may work with
let carsPromise = Car.find(
JSON.parse(carsFetchQuery(company, model, minPrice, maxPrice))
)
That's highly vulnerable for NoSQL injection.
A better approach would be like this one:
var query = []
var field = {}
field['company'] = {}
field['company']['$eq'] = company
query.push(field)
var field = {}
field['minPrice'] = {}
field['minPrice']['$gte'] = minPrice
query.push(field)
// or a bit shorter (thanks to turivishal)
query.push({ ['maxPrice']: { ['$eq']: maxPrice} })
let carsPromise = Car.find({$and: [ { $or: query } ] })
You an simply push as many conditions as you like with a loop. However, it is still possible to inject NoSQL code, for example when the URL looks like this:
...?model['$ne']=null
then the query would return all documents where model is not null - most likely all, see https://blog.websecurify.com/2014/08/hacking-nodejs-and-mongodb.html
Thus you should protect input values with mongo-sanitize or similar:
field['company']['$eq'] = sanitize(company)
