You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多筛选条件即时搜索功能优化及查询复用方案咨询

多过滤器搜索功能优化咨询

我想要构建一个包含多种过滤器的搜索功能,已经具备RangeSlider组件和获取对应最值的函数,筛选值会保存为对象,每次过滤器变更时即时发送至后端。

目前用if-else条件实现了原型,但这个方案不合理——过滤器数量增多后会完全无法维护。另外我还想优化整个筛选流程:当前每次请求都会检索整个集合,如果能基于前序搜索结果叠加新过滤器,而非再次全量检索,效率会大幅提升。请问该怎么实现?

价格与面积范围滑块过滤器界面


当前实现代码

前端

每次过滤器更新时,activeFilters会被发送至后端:

const activeFilters = reactive({ salePrice: '', space: '' })

async function updateFilter(minmax, property) {
  activeFilters[property] = minmax

  const filteredObjects = await $fetch('/api/properties/filtered', {
    method: 'POST',
    body: activeFilters,
  })

  return filteredObjects
}

后端

接收的请求体示例:{ "salePrice": { "min": 630000, "max": 850948 }, "space": { "min": 53, "max": 167 } }

export default defineEventHandler(async (event) => {
  const body = await readBody(event)

  try {
    if (body.salePrice !== '' && body.space !== '') {
      const properties = await Property.find({
        salePrice: { $gte: body.salePrice.min, $lte: body.salePrice.max },
        livableSurface: { $gte: body.space.min, $lte: body.space.max },
      })
      return properties
    }

    if (body.salePrice !== '') {
      const properties = await Property.find({
        salePrice: { $gte: body.salePrice.min, $lte: body.salePrice.max },
      })
      return properties
    }

    if (body.space !== '') {
      const properties = await Property.find({
        livableSurface: { $gte: body.space.min, $lte: body.space.max },
      })
      return properties
    }

    const properties = await Property.find()
    return properties
  } catch (err) {
    console.dir(err)
    event.res.statusCode = 500
    return {
      code: 'ERROR',
      message: 'Something went wrong.',
    }
  }
})

HTML

<InputsRangeSlider
  :config="salePriceSliderConfig"
  @updated-min-max="updateFilter($event, 'salePrice')"
/>

<InputsRangeSlider
  :config="spaceSliderConfig"
  @updated-min-max="updateFilter($event, 'space')"
/>

优化方案

1. 重构后端:动态构建查询条件,抛弃if-else

原来的if-else逻辑扩展性极差,新增过滤器就要加新的分支。可以通过动态生成MongoDB查询对象来解决:

export default defineEventHandler(async (event) => {
  const body = await readBody(event)
  const query = {}

  // 处理售价筛选(仅当min/max有效时添加条件)
  if (body.salePrice?.min !== undefined && body.salePrice?.max !== undefined) {
    query.salePrice = { 
      $gte: body.salePrice.min, 
      $lte: body.salePrice.max 
    }
  }

  // 处理面积筛选
  if (body.space?.min !== undefined && body.space?.max !== undefined) {
    query.livableSurface = { 
      $gte: body.space.min, 
      $lte: body.space.max 
    }
  }

  // 新增过滤器只需添加类似的判断逻辑,不用改原有代码
  // 例如新增房间数筛选:
  // if (body.roomCount?.min !== undefined) {
  //   query.roomCount = { $gte: body.roomCount.min }
  // }

  try {
    const properties = await Property.find(query)
    return properties
  } catch (err) {
    console.dir(err)
    event.res.statusCode = 500
    return {
      code: 'ERROR',
      message: '服务器出错,请稍后重试。'
    }
  }
})

这种方式不管加多少过滤器,只需要新增对应的字段处理逻辑即可,代码维护性大幅提升。

2. 基于前序结果的增量筛选实现

要避免每次全量检索,推荐用后端缓存查询会话的方案:

前端修改

新增会话ID存储,每次请求携带会话信息:

const activeFilters = reactive({ salePrice: '', space: '' })
let searchSessionId = null // 存储当前搜索会话ID

async function updateFilter(minmax, property) {
  activeFilters[property] = minmax

  const requestBody = {
    filters: activeFilters,
    sessionId: searchSessionId
  }

  const response = await $fetch('/api/properties/filtered', {
    method: 'POST',
    body: requestBody,
  })

  // 更新会话ID
  searchSessionId = response.sessionId
  return response.properties
}

后端核心逻辑

  1. 依赖Redis等缓存服务存储会话信息(包含历史查询条件、结果游标等)
  2. 收到请求后,优先读取sessionId对应的缓存数据
  3. 如果有历史会话:将新的过滤器与历史查询条件合并(新条件覆盖旧条件,或叠加,根据业务需求)
  4. 如果没有历史会话:用当前过滤器生成初始查询
  5. 执行查询后,将新的查询条件和会话ID存入缓存(设置合理过期时间,比如15分钟)
  6. 返回查询结果和新的sessionId

示例伪代码:

import Redis from 'ioredis'
const redis = new Redis()

export default defineEventHandler(async (event) => {
  const { filters, sessionId } = await readBody(event)
  let query = {}

  if (sessionId) {
    // 从缓存读取历史查询条件
    const cachedQuery = await redis.get(`search:${sessionId}`)
    if (cachedQuery) {
      query = JSON.parse(cachedQuery)
    }
  }

  // 合并新过滤器到查询对象
  if (filters.salePrice?.min !== undefined && filters.salePrice?.max !== undefined) {
    query.salePrice = { $gte: filters.salePrice.min, $lte: filters.salePrice.max }
  }
  if (filters.space?.min !== undefined && filters.space?.max !== undefined) {
    query.livableSurface = { $gte: filters.space.min, $lte: filters.space.max }
  }

  // 生成新的会话ID(如果没有的话)
  const newSessionId = sessionId || crypto.randomUUID()
  // 缓存查询条件,设置15分钟过期
  await redis.set(`search:${newSessionId}`, JSON.stringify(query), 'EX', 900)

  try {
    const properties = await Property.find(query)
    return {
      sessionId: newSessionId,
      properties
    }
  } catch (err) {
    console.dir(err)
    event.res.statusCode = 500
    return {
      code: 'ERROR',
      message: '服务器出错,请稍后重试。'
    }
  }
})

这种方案既实现了增量筛选的效率提升,又保证了扩展性,适合数据更新频率不高、对查询性能有要求的场景。


内容的提问来源于stack exchange,提问作者Philippe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 22:20:27