基于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
相关产品推荐
相关产品推荐

