Remix+Shopify Hydrogen中Firestore getDocs查询无文档返回问题
问题:Firebase Firestore在Shopify Hydrogen(Remix)中读取不到文档
调用getDocs(collection(db, "products"))返回空快照,已确认以下信息:
- 连接正常,读取请求已发送至Firestore
- Firebase配置信息正确
- Firestore的
products集合存在有效文档 - 安全规则处于测试模式(允许所有读写操作)
但日志显示querySnapshot的docs和oldDocs属性的root对象size均为0,fromCache为true,无报错信息,怀疑是区域或Remix环境问题,寻求排查方向与解决方案。
排查方向与解决方案
1. 强制从服务器读取,绕过缓存
fromCache: true说明当前读取的是本地缓存,但缓存中无数据。可以在查询时强制指定从服务器拉取:
// 修改业务代码中的getDocs调用 const querySnapshot = await getDocs(collection(db, 'products'), { source: 'server' });
2. 显式指定Firestore数据库区域
若Firestore数据库设置为北美区域,初始化时未指定区域可能导致跨区域连接异常。修改Firebase配置文件,显式指定区域:
// firebase-config.js import {initializeApp} from 'firebase/app'; import {getFirestore} from 'firebase/firestore'; const firebaseConfig = { apiKey: process.env.FIREBASE_API_KEY, authDomain: process.env.FIREBASE_AUTH_DOMAIN, projectId: process.env.FIREBASE_PROJECT_ID, storageBucket: process.env.FIREBASE_STORAGE_BUCKET, messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID, appId: process.env.FIREBASE_APP_ID, measurementId: process.env.FIREBASE_MEASUREMENT_ID, }; const app = initializeApp(firebaseConfig); const db = getFirestore(app); // 显式指定数据库区域,北美区域示例为"us-central1" db.settings({ location: 'us-central1' }); export default db;
3. 验证服务器端环境变量与访问权限
Remix的loader默认在服务器端执行,需确认:
- 服务器端环境变量已正确加载:在loader中打印
console.log(process.env.FIREBASE_PROJECT_ID)验证 - 服务器网络可访问Firestore:编写独立Node.js脚本测试读取,排除Remix环境干扰:
// test-firestore.js import { initializeApp } from 'firebase/app'; import { getFirestore, collection, getDocs } from 'firebase/firestore'; import dotenv from 'dotenv'; dotenv.config(); const firebaseConfig = { apiKey: process.env.FIREBASE_API_KEY, authDomain: process.env.FIREBASE_AUTH_DOMAIN, projectId: process.env.FIREBASE_PROJECT_ID, }; const app = initializeApp(firebaseConfig); const db = getFirestore(app); async function testRead() { const snap = await getDocs(collection(db, 'products')); console.log('文档数量:', snap.size); snap.forEach(doc => console.log('文档数据:', doc.data())); } testRead();
4. 检查集合名称大小写一致性
Firestore集合名称大小写敏感,确认代码中collection(db, "products")的名称与Firestore控制台中的集合名称完全一致(避免"Products"与"products"这类差异)。
5. 启用调试日志排查请求细节
开启Firestore调试日志,查看请求的详细过程与潜在错误:
// 在firebase-config.js中添加 import { setLogLevel } from 'firebase/firestore'; setLogLevel('debug');
附用户提供的相关代码
Firebase配置文件
import {initializeApp} from 'firebase/app'; import {getFirestore} from 'firebase/firestore'; const firebaseConfig = { apiKey: process.env.FIREBASE_API_KEY, authDomain: process.env.FIREBASE_AUTH_DOMAIN, projectId: process.env.FIREBASE_PROJECT_ID, storageBucket: process.env.FIREBASE_STORAGE_BUCKET, messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID, appId: process.env.FIREBASE_APP_ID, measurementId: process.env.FIREBASE_MEASUREMENT_ID, }; // Initialize Firebase const app = initializeApp(firebaseConfig); const db = getFirestore(app); export default db;
Remix业务代码
import db from '~/firebase-config'; import {collection, getDocs, query} from 'firebase/firestore'; ... export async function loader(args) { const criticalData = await loadCriticalData(args); return defer({...criticalData}); } async function loadCriticalData({context, params, request}) { const {handle} = params; const {storefront} = context; const products = []; // products array to store collection data if (!handle) { throw new Response(null, {status: 404}); } const [{product}, variants, querySnapshot] = await Promise.all([ context.storefront.query(PRODUCT_QUERY, { variables: { handle, selectedOptions: getSelectedProductOptions(request), }, }), context.storefront.query(VARIANTS_QUERY, { variables: {handle: params.handle}, }), getDocs(collection(db, 'products')), ]); // organize products collection array console.log('querySnap:', JSON.stringify(querySnapshot)); querySnapshot.forEach((doc) => { products.push(doc.data()); }); return { product, variants, products, }; }
querySnapshot日志示例
"_firestore": { "app": { ... }, "databaseId": { "projectId": "...", "database": "(default)" }, "settings": { ... } }, "_snapshot": { "query": { ... }, "docs": { "keyedMap": { "root": { "size": 0 } }, "sortedSet": { "root": { "size": 0 } } }, "oldDocs": { "keyedMap": { "root": { "size": 0 } }, "sortedSet": { "root": { "size": 0 } } }, "docChanges": [], "mutatedKeys": { "data": { "root": { "size": 0 } } }, "fromCache": true, "syncStateChanged": true, "excludesMetadataChanges": false, "hasCachedResults": false }, "metadata": { "hasPendingWrites": false, "fromCache": true }, "query": { "converter": null, "_query": { "path": { "segments": ["products"], "offset": 0, "len": 1 } } }, "type": "collection", "firestore": { ... } }
内容的提问来源于stack exchange,提问作者matrixvivi
相关产品推荐
相关产品推荐

