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

Next JS + MongoDB搜索功能异常排查请求

搜索功能失效排查:Next.js MongoDB API返回所有数据而非匹配结果

问题描述

我在开发Next.js API的搜索功能,该API存储燃油价格、加油站名称等数据。预期请求携带keyword参数时,仅返回匹配关键词的结果,但实际返回所有数据,和MongoDB普通find()函数的行为一致。

相关代码

ApiFeatures类代码

class ApiFeatures {
  constructor(query, queryStr) {
    this.query = query;
    this.queryStr = queryStr;
  }

  search() {
    const keyword = this.queryStr.keyword
      ? {
          $or: [   // 疑似问题点
            {
              name: {
                $regex: this.queryStr.keyword,
                $options: "i",
              },
            },
            {
              email: {
                $regex: this.queryStr.keyword,
                $options: "i",
              },
            },
            {
              // 怀疑此处字段名有误
              petrolPumpName: {
                $regex: this.queryStr.keyword,
                $options: "i",
              },
            },
          ],
        }
      : {};

    this.query = this.query.find({ ...keyword });
    return this;
  }
}

Next.js API处理函数

const handler = catchAsyncErrors(async (req, res) => {
      const apiFeature = new ApiFeatures(
          User.find().select("-role -verified"),
          req.query
      ).search();
      const users = await apiFeature.query;
      if (users.length === 0) {
          return res.status(404).json("No User Found");
      }
      return res.status(200).json(users);
});

export default connectToMongo(isAuthenticated(catchAsyncErrors(handler)));

失效现象(燃油API场景)

请求URL:http://localhost.com/fuelStation?keyword=AbcfuelStation
返回数据:

{
    "rate": 50,
    "quantity": 100,
    "amount": 5000,
    "fuelStationName": "Abc fuel Station"
  },
  {
    "rate": 50,
    "quantity": 100,
    "amount": 5000,
    "fuelStationName": "XYZ"
  }

不符合预期的是,未匹配关键词的XYZ加油站也被返回。

原因分析

  1. 字段名不匹配:
    代码中搜索燃油站名称用的是petrolPumpName,但实际数据中的字段是fuelStationName,导致该搜索条件完全失效。同时燃油站集合不存在name/email字段,$or中的这两个条件也无法匹配任何数据,最终搜索条件等价于空对象,返回所有数据。
  2. req.query.keyword未正确获取:
    若请求参数名拼写错误(如大小写不匹配)、中间件修改了req.query导致keyword丢失,或关键词为空字符串,都会使keyword变量变为空对象,触发find({})返回所有数据。
  3. 跨集合搜索逻辑混乱:
    同一个ApiFeatures类被用于用户和燃油站两个不同集合,搜索字段包含了双方的专属字段,导致在单个集合中查询时,多数条件无效,降低搜索准确性。

解决方法

1. 修正字段名匹配

将ApiFeatures.search()中的petrolPumpName改为实际字段名fuelStationName:

{
  fuelStationName: {
    $regex: this.queryStr.keyword,
    $options: "i",
  },
}

2. 优化跨集合搜索逻辑

让search方法支持自定义搜索字段,避免无效条件:

class ApiFeatures {
  constructor(query, queryStr) {
    this.query = query;
    this.queryStr = queryStr;
  }

  search(searchFields = ["name", "email"]) {
    if (!this.queryStr.keyword?.trim()) return this;

    const keywordRegex = {
      $regex: this.queryStr.keyword.trim(),
      $options: "i",
    };

    const orConditions = searchFields.map(field => ({ [field]: keywordRegex }));
    this.query = this.query.find({ $or: orConditions });
    return this;
  }
}

// 用户API调用
const apiFeature = new ApiFeatures(User.find().select("-role -verified"), req.query)
  .search(["name", "email"]);

// 燃油站API调用
const apiFeature = new ApiFeatures(FuelStation.find(), req.query)
  .search(["fuelStationName"]);

3. 排查参数获取问题

在API handler中添加日志,确认req.query.keyword的值:

const handler = catchAsyncErrors(async (req, res) => {
  console.log("Received keyword:", req.query.keyword);
  // 剩余代码不变
});

若日志显示undefined,需:

  • 检查请求URL的参数名是否为keyword(大小写敏感);
  • 确认isAuthenticated等中间件未修改或删除req.query中的keyword参数;
  • 验证Next.js默认的URL参数解析是否正常(默认配置支持)。

4. 处理空关键词场景

添加空值校验,避免空关键词触发全量返回:

search() {
  const keyword = this.queryStr.keyword?.trim()
    ? {
        $or: [
          { name: { $regex: this.queryStr.keyword.trim(), $options: "i" } },
          { email: { $regex: this.queryStr.keyword.trim(), $options: "i" } },
          { fuelStationName: { $regex: this.queryStr.keyword.trim(), $options: "i" } },
        ],
      }
    : {};

  this.query = this.query.find({ ...keyword });
  return this;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 00:27:05