mongodb Mongoose:如果查询中的参数为空,则忽略该参数

kx1ctssn  于 2023-03-17  发布在  Go
关注(0)|答案(7)|浏览(463)

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

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

它处理这样的请求:

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

这在color参数存在时有效,但是,如果color参数被省略,那么查询将搜索colorundefined的项,这不是我需要的行为。
在我的例子中,我想添加多个过滤器参数,如果它们不存在就会被忽略。我是否必须为每个例子创建一个单独的查询,或者是否有一个选项告诉Mongoose不要搜索一个为空或未定义的字段(在本例中为color)?

8nuwlpux

8nuwlpux1#

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

2uluyalo

2uluyalo2#

const query = Object.fromEntries(Object.entries(req.query).filter(([_,value]) => !!value))

Items.find({...query})

这将创建一个有用的查询对象,并且在parameter为空字符串的情况下也会有所帮助

w51jfk4q

w51jfk4q3#

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

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

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

注意如果你使用巴别塔,你可能需要先定义一个对象。

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

06odsfpq4#

您可以使用“解构赋值”来解包请求查询中的变量。

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不在原始查询中,它们将是 undefinedfalsy,因此将跳过该参数的if语句。

zpgglvta

zpgglvta5#

我也有这个问题。这是我的解决方案:

  • 在连接设置中添加ignoreUndefined
  • 我用的是雀巢
MongooseModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: async (configService: ConfigService) => ({
        uri: configService.get<string>('MONGO_URI'),
        useCreateIndex: true,
        useNewUrlParser: true,
        useFindAndModify: false,
        useUnifiedTopology: true,
        ignoreUndefined: true, // add this to the option
        connectionFactory: (connection) => {
          connection.plugin(require('mongoose-autopopulate'));
          return connection;
        },
      })
  • 这是查询日志:
Mongoose: entry.find({ field: undefined })
  • 然后我得到了所有的参赛作品
mutmk8jj

mutmk8jj6#

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

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

把上面的代码放在util中,并在任何地方重用它。

9njqaruj

9njqaruj7#

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

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

或者,可以使用reduce将查询中要查找的选项显式指定为数组,并仅使用非undefined的字段构造filter对象:

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”不在数组中,它也会忽略“size”,因为它不在查询中。

const items = await Items.find(filter);

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

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

很酷,虽然可以说可读性较差。

相关问题