Mongoose:如果为null,则忽略查询中的参数

时间:2018-03-22 19:25:22

标签: node.js mongodb rest express mongoose

我有一个简单的REST API,我想在特定端点上实现过滤。

想象一下,我有一个这样的端点:

localhost:5000/api/items?color="red"

处理这样的请求:

const items = await Items.find({color: req.query.color})

color参数存在时,此方法有效。但是,如果省略color参数,则查询会搜索colorundefined的项目。这不是我需要的行为。

在我的情况下,我想添加多个过滤器参数,如果它们不存在则会被忽略。我是否必须为每种情况创建一个单独的查询,或者是否有一个选项告诉Mongoose不搜索字段(在这种情况下为color),如果它为null或未定义?

5 个答案:

答案 0 :(得分:5)

您可以使用“destructuring assignment”在req.query中解压缩变量。

const { color } = req.query;
if(color) {
   const items = await Items.find({ color })
}

如果您有多个过滤器,则可以使用上面的变量。例如,您可能有colortype个参数。这样,您可以构建一个对象以传递给find方法。

const { color, type } = req.query;
let query = {};
if(color) {
   query.color = color;
}
if(type) {
   query.type = type;
}
const items = await Items.find(query);

如果colortype不在原始查询中,则它们将未定义falsy,因此将跳过该参数的if语句。 希望它有效!

答案 1 :(得分:5)

我刚刚遇到同样的问题,如果你使用ES6支持的节点版本,你应该可以使用spread。它会自动处理未定义的

var filters = {
     colour: "red",
     size: undefined
}


Items.find({...filters}) 
// only colour is defined, so it becomes
Items.find({colour:"red"})

注意如果您使用的是Babel。您可能需要先定义一个对象。

var query = {...filters}
Items.find(query)

答案 2 :(得分:1)

在传递对象之前,您可以从对象中删除未定义的键

Object.keys(filter).forEach(key => filter[key] === undefined && delete filter[key])

将上述代码放入util中,并在各处重复使用。

答案 3 :(得分:1)

如 francisct 所述,您可以通过在连接选项中使用 ignoreUndefined 来实现这一点,而无需执行任何手动检查:

const mongoose = require('mongoose');
mongoose.connect(mongoDb, { ignoreUndefined: true });

或者,您可以使用 reduce 将您在查询中查找的选项显式指定为数组,并仅使用不是 undefined 的字段构造过滤器对象:

const query = { color: 'red', price: 2, hello: 'world' };
const fields = ['color', 'price', 'size'];

function getFilter(query, fields) {
  return fields.reduce((filter, field) => {

    if (query[field] !== undefined)
      return {
        [field]: query[field],
        ...filter,
      };

    return filter;
  }, {});
}

const filter = getFilter(query, fields); // { price: 2, color: 'red' }

在这种情况下,函数不会向对象添加“hello”字段,因为“hello”不在数组中。它还忽略“大小”,因为它不在查询中。您可以像这样使用返回的对象:

const items = await Items.find(filter);

您可以使用隐式返回和三元运算符来缩短此函数:

const getFilter = (query, fields) => fields.reduce(
  (filter, field) => query[field] !== undefined ? {
    [field]: query[field],
    ...filter,
  } : filter, {}
);

很酷,但可读性较差。

答案 4 :(得分:0)

连接到 MongoDB 时,您可以在连接选项中使用 ignoreUndefined,以便在您的查询中,所有未定义的键在序列化为 BJSON 时都会被跳过。您可以在此 page

上看到选项