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

Firebase实时数据库equalTo()查询异常(React Native Expo)

问题:Firebase实时数据库基于ShopNo随机查询失败

错误表现

成功生成随机ShopNo,但查询时抛出错误:TypeError: undefined is not a function (near '...ualTo)(random)).then(function (snapshot)...')

数据库结构

{
  "Bakery": {
    "Bakery Cuisine": {
      "Description": "Within North Spine Plaza",
      "Halal": "Yes",
      "Latitude": 1.34714,
      "Location": "50 Nanyang Ave, #01-20 North Spine Plaza, Singapore 639798",
      "Longitude": 103.68066,
      "OH": "Mon - Sat : 8 AM to 7 PM, Sun Closed",
      "ShopNo": 1
    }
  },
  "Beverage": {
    "Beverage": {
      "Description": "Within the South Spine food court",
      "Halal": "No",
      "Latitude": 1.34253,
      "Location": "21 Nanyang Link, Singapore 637371",
      "Longitude": 103.68243,
      "OH": "Mon - Fri: 7 30 am to 8 pm, Sat - Sun/PH Closed",
      "ShopNo": 2
    },
    "Beverages": {
      "Description": "Within North Spine Koufu",
      "Halal": "No",
      "Latitude": 1.34708,
      "Location": "76 Nanyang Dr, #02-03 North Spine Plaza, Singapore 637331",
      "Longitude": 103.68002,
      "OH": "Mon - Fri : 7 am to 8 pm, Sat : 7 am to 3 pm, Sun Closed",
      "ShopNo": 3
    },
    "Boost": {
      "Description": "Within North Spine Plaza",
      "Halal": "No",
      "Latitude": 1.34735,
      "Location": "50 Nanyang Ave, #01-11 North Spine Plaza, Singapore 639798",
      "Longitude": 103.68036,
      "OH": "Mon - Fri : 10 am to 9 pm, Sat - Sun: 10 am to 6 pm",
      "ShopNo": 4
    }
  },
  "Total": 89
}

错误代码示例

初始代码

import { StyleSheet, Text, View, TouchableOpacity } from 'react-native'
import { useNavigation } from '@react-navigation/core'
import {db} from '../firebase'
import React, {useEffect, useState} from 'react'
import {ref, get, orderByChild, equalTo} from 'firebase/database'

const SubScreen2 = () => {
  const navigation = useNavigation()
  const [todoData, setToDoData] = useState([])
  
  useEffect (() => {
    var random = 0
    get(ref(db, "food/Total")).then(snapshot => {
      const count = snapshot.val();
      random = Math.floor((Math.random() * count));
      console.log(random) //Random number generated (Successful)
      ref(db, `food/`), orderByChild("ShopNo"), equalTo(random)  //Failed
      .then(snapshot => {
        const data = snapshot.val() 
        setToDoData(data)
      })
    })
  },[]) 
  console.log(todoData)
}

更新后代码

import {ref, get, orderByChild, equalTo, query} from 'firebase/database'
const SubScreen2 = () => {
  const navigation = useNavigation()
  const [todoData, setToDoData] = useState([])
  
  useEffect (() => {
    var random = 0
    get(ref(db, "food/Total")).then(snapshot => {
      const count = snapshot.val();
      random = Math.floor((Math.random() * count));
      console.log(random)
      query(ref(db, `food/`), orderByChild("ShopNo"), equalTo(random))
      .then(snapshot => {
        const data = snapshot.val()
        setToDoData(data)
      })
    })
  },[]) 
  console.log(todoData)
}

问题根源

  1. 查询方法调用错误:query函数仅用于构建查询条件对象,不能直接通过.then()获取数据,必须配合get()方法执行查询。
  2. 数据层级不匹配:ShopNo字段存储在food/[分类]/[店铺]的三级节点下,直接在food/节点使用orderByChild("ShopNo")会查找food的直接子节点(如Bakery、Beverage)的ShopNo字段,而这些节点本身没有该字段,因此无法匹配到目标数据。

解决方案

方案一:重构数据库(推荐,提升查询效率)

将所有店铺数据扁平化存储到一个统一节点(如shops),避免嵌套分类层级,方便直接查询:

{
  "shops": {
    "shop1": {
      "Category": "Bakery",
      "Name": "Bakery Cuisine",
      "ShopNo": 1,
      "Description": "Within North Spine Plaza",
      "Halal": "Yes",
      "Latitude": 1.34714,
      "Location": "50 Nanyang Ave, #01-20 North Spine Plaza, Singapore 639798",
      "Longitude": 103.68066,
      "OH": "Mon - Sat : 8 AM to 7 PM, Sun Closed"
    },
    "shop2": {
      "Category": "Beverage",
      "Name": "Beverage",
      "ShopNo": 2,
      "Description": "Within the South Spine food court",
      "Halal": "No",
      "Latitude": 1.34253,
      "Location": "21 Nanyang Link, Singapore 637371",
      "Longitude": 103.68243,
      "OH": "Mon - Fri: 7 30 am to 8 pm, Sat - Sun/PH Closed"
    }
  },
  "Total": 89
}

对应修正后的代码:

import { StyleSheet, Text, View, TouchableOpacity } from 'react-native'
import { useNavigation } from '@react-navigation/core'
import { db } from '../firebase'
import React, { useEffect, useState } from 'react'
import { ref, get, orderByChild, equalTo, query } from 'firebase/database'

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

  useEffect(() => {
    // 获取店铺总数并生成随机ShopNo(注意ShopNo从1开始,需+1避免生成0)
    get(ref(db, "food/Total"))
      .then(totalSnapshot => {
        const count = totalSnapshot.val();
        const randomShopNo = Math.floor(Math.random() * count) + 1;
        console.log(randomShopNo)

        // 构建查询并执行get请求获取数据
        const shopQuery = query(
          ref(db, "food/shops"),
          orderByChild("ShopNo"),
          equalTo(randomShopNo)
        )
        return get(shopQuery)
      })
      .then(shopSnapshot => {
        if (shopSnapshot.exists()) {
          // query返回的是对象,取第一个匹配的店铺数据
          const shopData = Object.values(shopSnapshot.val())[0]
          setToDoData(shopData)
        } else {
          console.log("未找到匹配的店铺")
        }
      })
      .catch(error => {
        console.error("查询出错:", error)
      })
  }, [])

  return (
    <View style={styles.container}>
      {todoData.Name && (
        <View>
          <Text style={styles.shopName}>{todoData.Name}</Text>
          <Text>分类:{todoData.Category}</Text>
          <Text>地址:{todoData.Location}</Text>
        </View>
      )}
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    justifyContent: 'center'
  },
  shopName: {
    fontSize: 20,
    fontWeight: 'bold',
    marginBottom: 10
  }
})

export default SubScreen2

方案二:保留原数据库结构(效率较低)

如果无法修改数据库,需要先获取所有分类,再遍历每个分类下的店铺查找匹配的ShopNo:

import { StyleSheet, Text, View, TouchableOpacity } from 'react-native'
import { useNavigation } from '@react-navigation/core'
import { db } from '../firebase'
import React, { useEffect, useState } from 'react'
import { ref, get } from 'firebase/database'

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

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

        // 获取所有分类数据
        return get(ref(db, "food"))
      })
      .then(foodSnapshot => {
        const foodData = foodSnapshot.val();
        // 遍历分类,跳过Total字段
        for (const category in foodData) {
          if (category === "Total") continue;
          const shops = foodData[category];
          // 遍历分类下的店铺
          for (const shopName in shops) {
            const shop = shops[shopName];
            if (shop.ShopNo === randomShopNo) {
              setToDoData({...shop, Category: category, Name: shopName})
              return; // 找到后终止遍历
            }
          }
        }
        console.log("未找到匹配的店铺")
      })
      .catch(error => {
        console.error("查询出错:", error)
      })
  }, [])

  return (
    <View style={styles.container}>
      {todoData.Name && (
        <View>
          <Text style={styles.shopName}>{todoData.Name}</Text>
          <Text>分类:{todoData.Category}</Text>
          <Text>地址:{todoData.Location}</Text>
        </View>
      )}
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    justifyContent: 'center'
  },
  shopName: {
    fontSize: 20,
    fontWeight: 'bold',
    marginBottom: 10
  }
})

export default SubScreen2

内容的提问来源于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.29 18:47:24