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

Posted

技术标签:

【中文标题】Mongoose:如果查询中的参数为空,则忽略该参数【英文标题】:Mongoose: ignore parameter in query if it is null 【发布时间】:2018-09-01 09:03:28 【问题描述】:

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

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

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

处理这样的请求:

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

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

在我的情况下,我想添加 多个过滤器参数,如果它们不存在,它们将被忽略。我是否必须为每个案例创建单独的查询,或者是否可以选择告诉 Mongoose 不要搜索字段(在本例中为 color)如果它是 null 或未定义?

【问题讨论】:

【参考方案1】:

您可以使用“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 语句。 希望它有效!

【讨论】:

这是我希望避免的,因为如果我有 5 个以上的参数,我需要对每种可能性进行查询,即 32。 我刚刚进行了更新。您认为以下解决方案对您有用吗?【参考方案2】:

我刚刚遇到了同样的问题,如果你使用的是支持 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)

【讨论】:

【参考方案3】:

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

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

把上面的代码放在 util 里面,到处重复使用。

【讨论】:

【参考方案4】:

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

【讨论】:

【参考方案5】:

正如 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, 
);

很酷,尽管可读性差。

【讨论】:

【参考方案6】:

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

在连接设置中添加ignoreUndefined

我正在使用nestjs

    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 )
然后我得到了所有的条目

【讨论】:

以上是关于Mongoose:如果查询中的参数为空,则忽略该参数的主要内容,如果未能解决你的问题,请参考以下文章

SQL 选择不同的行,如果为空则忽略行

mongodb/mongoose:如果来自nestjs的数据不为空,则保存唯一值

Spring boot:Query方法中的可选参数查询

Typescript Mongoose 以类型安全的方式忽略查询结果中的某些字段

如何使用连接表检查房间查询中的空参数?

Python中SQL语句当查询多个条件,如果条件为空,则不加入查询条件;如果条件不为空,则加入查询条件