【问题标题】:Is it possible to create MongoDB query dynamically on the basis of input vaiables or can we inject string into MongoDB是否可以根据输入变量动态创建 MongoDB 查询,或者我们可以将字符串注入 MongoDB
【发布时间】:2022-01-19 18:53:52
【问题描述】:

我想根据输入变量创建一个动态的 MongoDB 查询 我尝试将查询作为字符串,但它不起作用。

let carsPromise = Car.find({
   carsFetchQuery(company, model, minPrice, maxPrice),
  })
    .skip(offSet)
    .limit(rowsPerPage)
    .lean();

输入参数不为空时动态创建获取查询的功能

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)}
     }],
    },
  ]
  `;

获取查询表达式的辅助函数

const getQuery = (opertor, key, value) => {
  if (value) {
    return `${key}: {${opertor}: '${value}'}`;
  }
  return '';
};

但它没有任何帮助

【问题讨论】:

  • 你想动态构建一个object/array结构,不是字符串。是的,完全可以动态创建对象并放入数组…

标签: mongodb mongoose


【解决方案1】:

您不能在查询中注入字符串,但您可以在查询中传递一个对象,准备一个对象数组并在查询中使用它,

为了理解我已经更新了您的方法如下,您可以根据您的要求进行更改,

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));

并在您的查询中使用它,但请确保您已通过 async/await 方法包装您的查询,

let carsPromise = await Car.find(
   carsFetchQuery(company, model, minPrice, maxPrice)
)
.skip(offSet)
.limit(rowsPerPage)
.lean();

【讨论】:

    【解决方案2】:

    find 需要一个 JSON 对象,因此它可以使用

    let carsPromise = Car.find(
       JSON.parse(carsFetchQuery(company, model, minPrice, maxPrice))
    )
    

    这对于 NoSQL 注入非常脆弱。

    更好的方法是这样的:

    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 } ] })
    

    您可以使用循环简单地推送任意数量的条件。但是,仍然可以注入 NoSQL 代码,例如当 URL 如下所示时:

    ...?model['$ne']=null
    

    然后查询将返回model 不为空的所有文档 - 很可能是所有文档,请参阅https://blog.websecurify.com/2014/08/hacking-nodejs-and-mongodb.html

    因此,您应该使用mongo-sanitize 或类似名称来保护输入值:

    field['company']['$eq'] = sanitize(company)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多