V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
PeakFish
V2EX  ›  Node.js

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

  •  1
     
  •   PeakFish · 2021-09-19 20:41:04 +08:00 · 6067 次点击
    这是一个创建于 1198 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    const findList = await userModel
      // mongoose 的查找方法
      .find({
        nickname: { $regex: nicknameReg },
        _id: id ? ObjectId(id) : '查询字段的所有状态 或者 不查询这个字段, 这块需要怎么写?',
        status: status ? status : '查询字段的所有状态 或者 不查询这个字段, 这块需要怎么写?'
      })
    
    7 条回复    2021-12-31 15:00:26 +08:00
    indo
        1
    indo  
       2021-09-19 21:29:51 +08:00 via iPhone   ❤️ 1
    我的想法应该是在函数入口加下判断,是否有入参,有责用入参,没有则空。
    dream4ever
        2
    dream4ever  
       2021-09-19 23:45:05 +08:00   ❤️ 2
    ```js
    const query = {
    nickname: { $regex: nicknameReg }
    }

    if (id) {
    query._id = ObjectId(id)
    }
    if (status) {
    query.status = status
    }

    const findList = await userModel.find(query)
    ```
    tukon479
        3
    tukon479  
       2021-09-21 19:31:29 +08:00
    用 $and 和 $or 就行了

    `{ $and: [ { $or: [_id ? {_id}: {}] } , { $or: [ status ? {status} : {} ] } ] }`
    ChangJingli
        4
    ChangJingli  
       2021-11-09 11:03:32 +08:00
    @dream4ever 目前 where 条件都是这么写的,条件多的时候感觉很不优雅
    dream4ever
        5
    dream4ever  
       2021-11-09 21:03:36 +08:00
    @ChangJingli 忽然想到其实可以把这个常用的需求封装成一个方法,做一层抽象,用起来就能“优雅”一点了
    ChangJingli
        6
    ChangJingli  
       2021-11-10 09:46:31 +08:00
    @dream4ever 提取到 service 层仍是这样拼 where 条件;我尝试过封装公共 util 过滤条件,然而发现过滤条件跟业务有强耦合,util 不知道你什么时候需要保留空字符串,什么时候不需要,`null`类型 亦如此。
    ouxch
        7
    ouxch  
       2021-12-31 15:00:26 +08:00
    最笨的办法当然就是写几个条件分支来组装最终的查询条件,例如:

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

    ---

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

    <br/>

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

    ```javascript
    const { reject, isNil } = require('ramda')
    const omitNil = reject(isNil)
    ```

    做个解释:

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

    将 `reject` 和 `isNil` 进行组合,得到 `omitNil` 函数,它的作用是:排除掉值为 `null` 或 `undefined` 的元素


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

    ```javascript
    const obj = { a: 1, b: null, c: undefined }
    omitNil(obj) // => { a: 1 }
    obj // => { a: 1, b: null, c: undefined }

    const arr = [1, null, undefined]
    omitNil(arr) // => [ 1 ]
    arr // => [1, null, undefined]
    ```

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

    <br/>

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

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

    <br/>

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

    <br/>

    > 参考:
    >
    > https://ramda.cn
    >
    > https://ramdajs.com/
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1056 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 19:40 · PVG 03:40 · LAX 11:40 · JFK 14:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.