Nodejs mongoose 查找 find,当前端没有传过来筛选参数的时候,查找条件这块应该怎么写?

发布于 1周前 作者 songsunli 来自 nodejs/Nestjs

Nodejs mongoose 查找 find,当前端没有传过来筛选参数的时候,查找条件这块应该怎么写?

上代码,下面的 id 字段 和 status 字段,如果前端没有传过来这个字段,那就 去掉筛选 或 者查询全部。这块应该怎么写?

const findList = await userModel
  // mongoose 的查找方法
  .find({
    nickname: { $regex: nicknameReg },
    _id: id ? ObjectId(id) : '查询字段的所有状态 或者 不查询这个字段, 这块需要怎么写?',
    status: status ? status : '查询字段的所有状态 或者 不查询这个字段, 这块需要怎么写?'
  })

8 回复

我的想法应该是在函数入口加下判断,是否有入参,有责用入参,没有则空。


js<br>const query = {<br> nickname: { $regex: nicknameReg }<br>}<br><br>if (id) {<br> query._id = ObjectId(id)<br>}<br>if (status) {<br> query.status = status<br>}<br><br>const findList = await userModel.find(query)<br>

用 $and 和 $or 就行了

{ $and: [ { $or: [_id ? {_id}: {}] } , { $or: [ status ? {status} : {} ] } ] }

目前 where 条件都是这么写的,条件多的时候感觉很不优雅

忽然想到其实可以把这个常用的需求封装成一个方法,做一层抽象,用起来就能“优雅”一点了

提取到 service 层仍是这样拼 where 条件;我尝试过封装公共 util 过滤条件,然而发现过滤条件跟业务有强耦合,util 不知道你什么时候需要保留空字符串,什么时候不需要,null类型 亦如此。

最笨的办法当然就是写几个条件分支来组装最终的查询条件,例如:

javascript<br>const filter = { nickname: { $regex: nicknameReg } }<br>if (!!id) fiter._id = ObjectId(id)<br>if (!!status) fiter.status = status<br>const findList = await userModel.find(filter)<br>



其实这是一个如何让编码更加优雅的问题,不只适用于此处你这个问题,如果从事JavaScript开发,建议了解下函数式编程,这里以函数式编程库 [ramda]( https://ramda.cn/) 为例,看看写出来又是怎样的:

<br/>

首先定义一个通用的纯函数 omitNil

javascript<br>const { reject, isNil } = require('ramda')<br>const omitNil = reject(isNil)<br>

做个解释:

isNilreject 都是 ramda 直接提供的函数,并且 ramda 的函数都是自动柯里化的;
isNil 的作用:检测输入值是否为 nullundefined
reject 的作用:可视为 filter 的补操作,简言之 filter 是留下满足条件的元素、reject 是排除满足条件的元素;

rejectisNil 进行组合,得到 omitNil 函数,它的作用是:排除掉值为 nullundefined 的元素


做一个简单直观的测试,看看 omitNil 函数的作用:

javascript<br>const obj = { a: 1, b: null, c: undefined }<br>omitNil(obj) // =&gt; { a: 1 }<br>obj // =&gt; { a: 1, b: null, c: undefined }<br><br>const arr = [1, null, undefined]<br>omitNil(arr) // =&gt; [ 1 ]<br>arr // =&gt; [1, null, undefined]<br>

可以看到,omitNil 的返回值和输入参数相比,少了值为 nullundefined 的元素,并且没有修改原输入参数

<br/>

现在回到楼主的问题,就可以一行代码实现了:

javascript<br>const findList = await userModel.find(omitNil({ nickname: { $regex: nicknameReg }, _id: id, status }))<br>

<br/>

最后,ramda 的核心设计理念就包含了:数据不变性和函数无副作用,因此以上纯函数均不会改变输入参数的值。

<br/>

> 参考:
>
> https://ramda.cn
>
> https://ramdajs.com/

在Node.js中使用Mongoose进行数据库查询时,如果前端没有传递筛选参数,我们通常需要一个默认的全量查询条件。Mongoose的find方法可以接受一个空的查询对象{}来表示查找所有文档。以下是一个简单的示例,展示了如何处理前端可能未传递筛选参数的情况:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// 假设我们有一个User模型
const userSchema = new Schema({
  name: String,
  age: Number,
  email: String
});

const User = mongoose.model('User', userSchema);

// 假设前端可能传递一个filter对象,如 { name: 'John' }
app.get('/users', async (req, res) => {
  const filter = req.query.filter ? JSON.parse(req.query.filter) : {};

  try {
    const users = await User.find(filter);
    res.json(users);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

// 示例:启动服务器并连接MongoDB(需替换为实际连接字符串)
mongoose.connect('mongodb://localhost:27017/mydatabase', { useNewUrlParser: true, useUnifiedTopology: true });

const app = require('express')();
app.listen(3000, () => console.log('Server started on port 3000'));

在这个例子中,如果前端没有传递filter参数,filter将是一个空对象{},Mongoose的find方法将返回所有用户文档。如果传递了filter参数,它将被解析并用作查询条件。注意,解析来自前端的JSON时要小心,确保进行必要的验证和清理以防止安全漏洞。

回到顶部