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

基于Firebase Functions服务端实现多条件过滤(React JS)

基于Firebase Cloud Functions实现多条件宠物数据过滤

一、前置准备

  • 确保本地安装Firebase CLI,已初始化项目并启用Cloud Functions和Firestore服务
  • 进入项目根目录,执行cd functions切换到Functions目录,安装依赖:npm install firebase-admin express cors

二、编写Cloud Functions HTTP端点

创建处理过滤请求的HTTP函数,读取URL查询参数动态构建Firestore查询,支持多条件过滤与分页:

const functions = require("firebase-functions");
const admin = require("firebase-admin");
const express = require("express");
const cors = require("cors");

admin.initializeApp();
const db = admin.firestore();
const app = express();

app.use(cors({ origin: true })); // 允许前端跨域请求

app.get("/filter", async (req, res) => {
  try {
    const {
      activeCategory,
      activeAnimal,
      activeHairType,
      activeGender,
      activeEyesType,
      hasCollar,
      lastDocId,
      limit = 10
    } = req.query;

    let query = db.collection("blogs");

    // 动态添加过滤条件
    if (activeCategory && activeCategory !== "All") {
      query = query.where("category", "==", activeCategory);
    }
    if (activeAnimal && activeAnimal !== "All") {
      query = query.where("animal", "==", activeAnimal);
    }
    if (activeHairType && activeHairType !== "All") {
      query = query.where("hairType", "==", activeHairType);
    }
    if (activeGender && activeGender !== "All") {
      query = query.where("gender", "==", activeGender);
    }
    if (activeEyesType && activeEyesType !== "All") {
      query = query.where("eyesType", "==", activeEyesType);
    }
    if (hasCollar !== undefined && hasCollar !== "All") {
      query = query.where("hasCollar", "==", hasCollar === "yes");
    }

    // 分页处理:从指定文档后开始查询
    if (lastDocId) {
      const lastDoc = await db.collection("blogs").doc(lastDocId).get();
      if (lastDoc.exists) {
        query = query.startAfter(lastDoc);
      }
    }

    // 按时间戳降序排序并限制返回数量
    query = query.orderBy("timestamp", "desc").limit(parseInt(limit));

    const snapshot = await query.get();
    const blogs = snapshot.docs.map(doc => ({
      id: doc.id,
      ...doc.data()
    }));

    // 返回数据与分页标记
    res.status(200).json({
      blogs,
      lastDocId: blogs.length > 0 ? blogs[blogs.length - 1].id : null,
      hasMore: blogs.length === parseInt(limit)
    });
  } catch (error) {
    functions.logger.error("过滤请求失败:", error);
    res.status(500).json({ error: "服务器内部错误" });
  }
});

// 导出HTTP函数
exports.api = functions.https.onRequest(app);

三、部署Cloud Functions

在Functions目录执行命令完成部署:

firebase deploy --only functions

部署成功后会得到类似https://<region>-<project-id>.cloudfunctions.net/api/filter的API端点地址。

四、修改React前端代码

替换原fetchData逻辑,改为调用API处理过滤参数与分页:

const [blogs, setBlogs] = useState([]);
const [loading, setLoading] = useState(false);
const [lastDocId, setLastDocId] = useState(null);
const [hasMore, setHasMore] = useState(true);

// 发起过滤请求的函数
const fetchFilteredBlogs = async (resetPage = false) => {
  setLoading(true);
  try {
    const params = new URLSearchParams();
    // 拼接过滤参数
    if (activeCategory !== "All") params.append("activeCategory", activeCategory);
    if (activeAnimal !== "All") params.append("activeAnimal", activeAnimal);
    if (activeHairType !== "All") params.append("activeHairType", activeHairType);
    if (activeGender !== "All") params.append("activeGender", activeGender);
    if (activeEyesType !== "All") params.append("activeEyesType", activeEyesType);
    if (hasCollar !== "All") params.append("hasCollar", hasCollar);
    if (!resetPage && lastDocId) params.append("lastDocId", lastDocId);

    const response = await fetch(`https://<region>-<project-id>.cloudfunctions.net/api/filter?${params}`);
    const data = await response.json();

    // 更新状态:重置分页或追加数据
    if (resetPage) {
      setBlogs(data.blogs);
    } else {
      setBlogs(prev => [...prev, ...data.blogs]);
    }
    setLastDocId(data.lastDocId);
    setHasMore(data.hasMore);
    setFilters(data.blogs);
    setActive("home");
  } catch (error) {
    console.error("获取过滤数据失败:", error);
  } finally {
    setLoading(false);
  }
};

// 监听过滤条件变化,重置分页
useEffect(() => {
  setLastDocId(null);
  setHasMore(true);
  fetchFilteredBlogs(true);
}, [activeCategory, activeGender, activeAnimal, activeHairType, activeEyesType, hasCollar]);

// 加载更多数据(按需使用)
const loadMore = () => {
  if (hasMore && !loading) {
    fetchFilteredBlogs(false);
  }
};

五、关键注意事项

  • 复合索引创建:当查询包含多个where条件+orderBy时,Firestore控制台会提示创建复合索引,按提示操作即可。
  • 参数校验:可在Functions中添加参数合法性校验,避免非法参数导致查询异常。
  • 性能优化:对高频过滤组合可创建预聚合集合,或启用Firestore缓存减少重复查询。
  • 布尔字段处理:注意hasCollar这类布尔参数的转换,确保前端传递的"yes"/"no"正确映射为Firestore的布尔值。

内容的提问来源于stack exchange,提问作者Cindy Ortega Palma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 22:35:20