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

React Native Expo中Firebase实时数据库特定节点获取失败

问题原因分析

  1. 查询层级不匹配:你的ShopNo字段存储在二级节点(如food/Bakery/Bakery Cuisine/ShopNo),但查询是在food/根节点执行的。Firebase实时数据库的orderByChild仅会查找当前节点直接子节点的指定字段,而food/的直接子节点是Bakery、Beverage、Total——这些节点本身没有ShopNo字段,因此查询返回空结果,第一段代码的forEach循环根本不会触发,自然没有相关日志输出。
  2. 空值未校验:第二段代码中,当查询无结果时,getFirstChild函数返回null,但后续代码直接访问shopSnapshot.key,导致Cannot read properties of null (reading 'key')的空指针错误。

解决方案

方案1:扁平化数据库结构(推荐,符合Firebase最佳实践)

Firebase实时数据库更适合扁平化数据结构,建议将所有店铺数据直接放在统一节点下,把分类作为店铺的一个字段,避免嵌套层级:

{
  "food": {
    "shops": {
      "Bakery Cuisine": {
        "Category": "Bakery",
        "Description": "Within North Spine Plaza",
        "Halal": "Yes",
        "ShopNo": 1,
        // 其他字段...
      },
      "Beverage": {
        "Category": "Beverage",
        "ShopNo": 2,
        // 其他字段...
      }
    },
    "Total": 89
  }
}

之后修改查询路径,直接针对shops节点查询:

const SubScreen2 = () => {
  const navigation = useNavigation()
  const [todoData, setToDoData] = useState([])

  useEffect(() => {
    get(ref(db, "food/Total")).then(snapshot => {
      const count = snapshot.val();
      const random = Math.floor(Math.random() * count);
      console.log(random);

      // 修正查询路径为food/shops
      const rc = query(ref(db, `food/shops`), orderByChild("ShopNo"), equalTo(random))
      get(rc)
        .then((querySnapshot) => {
          querySnapshot.forEach((shopSnapshot) => {
            console.log("Randomly selected shop: " + shopSnapshot.key);
            console.log("Shop data", shopSnapshot.val());
          });
        })
        .catch(error => {
          console.log(error);
        });
    });
  }, []); // 修正useEffect依赖数组,避免无限循环

  return <View />; // 补充组件返回值
}

注意:需要在Firebase控制台的数据库规则中添加索引,提升查询性能:

{
  "rules": {
    "food": {
      "shops": {
        ".indexOn": ["ShopNo"]
      }
    }
  }
}

方案2:保留现有结构,遍历分类查询

如果不想修改数据库结构,需要先获取所有分类节点,再逐个查询每个分类下的店铺:

const SubScreen2 = () => {
  const navigation = useNavigation()
  const [todoData, setToDoData] = useState([])

  useEffect(() => {
    // 先获取所有分类节点
    get(ref(db, "food/")).then(categorySnapshot => {
      const categories = [];
      categorySnapshot.forEach(child => {
        if (child.key !== "Total") { // 跳过Total节点
          categories.push(child.key);
        }
      });

      // 获取店铺总数并生成随机ShopNo
      get(ref(db, "food/Total")).then(totalSnap => {
        const count = totalSnap.val();
        const random = Math.floor(Math.random() * count);
        console.log(random);

        // 遍历所有分类执行查询
        const queryPromises = categories.map(category => {
          return get(query(ref(db, `food/${category}`), orderByChild("ShopNo"), equalTo(random)));
        });

        Promise.all(queryPromises).then(results => {
          results.forEach(querySnapshot => {
            querySnapshot.forEach(shopSnapshot => {
              console.log("Randomly selected shop: " + shopSnapshot.key);
              console.log("Shop data", shopSnapshot.val());
            });
          });
        }).catch(err => console.error(err));
      });
    });
  }, []);

  return <View />;
}

方案3:空值校验,避免报错(针对第二段代码)

如果要保留原封装函数,必须在使用返回值前校验是否为null:

getFirstChild(rc)
  .then((shopSnapshot) => {
    if (!shopSnapshot) {
      console.log(`No shop found with ShopNo: ${random}`);
      return; // 无结果时直接返回
    }
    const shopKey = shopSnapshot.key;
    console.log("Randomly selected shop: " + shopKey);
    const shopData = shopSnapshot.val();
    console.log("Shop data", shopData);
  })
  .catch(error => {
    console.log(error);
  });

内容的提问来源于stack exchange,提问作者L.Calvin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 00:15:06