javascript 在React Native中从Firebase实时数据库进行地理查询时数据不一致

zhte4eai  于 2023-04-19  发布在  Java
关注(0)|答案(1)|浏览(95)
const [location, setLocation] = useState<any>()
  const userId = '1234'

  const updateUserLocation = async (position: any) => {
    const { latitude, longitude } = position.coords
    await database()
      .ref(`usersLocations/${userId}`)
      .set(encodeLocationObject({ latitude, longitude }))
    console.log('location updated')
  }

  useEffect(() => {
    let watchId: number

    const handleLocationChange = async (position: any) => {
      setLocation(position)
      await updateUserLocation(position)

      setTimeout(async () => {
        const nearbyUsers = await findNearbyUsers(position)
        console.log(nearbyUsers)
      }, 5000)
    }

    const startWatchingLocation = async () => {
      watchId = Geolocation.watchPosition(
        handleLocationChange,
        error => {
          Alert.alert(`Error getting location: ${error.message}`)
        },
        {
          enableHighAccuracy: true,
          distanceFilter: 10,
        },
      )
    }

    startWatchingLocation()

    return () => {
      Geolocation.clearWatch(watchId)
    }
  }, [])
export const findNearbyUsers = async (userLocation: GeoPosition) => {
  try {
    const {latitude, longitude} = userLocation.coords
    const geohash = ngeohash.encode(latitude, longitude)

    const RADIUS = USER_DISCOVER_RANGE + 50
    const center = ngeohash.decode(geohash)
    const latPerMeter = 1 / 111111
    const lonPerMeter = Math.abs(Math.cos(center.latitude) * latPerMeter)

    const latMin = center.latitude - latPerMeter * RADIUS
    const latMax = center.latitude + latPerMeter * RADIUS
    const lonMin = center.longitude - lonPerMeter * RADIUS
    const lonMax = center.longitude + lonPerMeter * RADIUS

    const dbRef = database()
      .ref('usersLocations')
      .orderByChild('g')
      .startAt(ngeohash.encode(latMin, lonMin))
      .endAt(ngeohash.encode(latMax, lonMax))

    const users = (await dbRef.once('value')).val()
    const currentUserID = '123'
    let nearbyUsers: Array<suggestedUser> = []

    console.log(Object.keys(users));
    

    for (let userID of Object.keys(users)) {
      if (userID !== currentUserID) {
        const otherLocation = users[userID].l
        // console.log({latitude, longitude}, otherLocation)
        const distance = getDistance({latitude, longitude}, otherLocation)
        console.log(userID, distance);
        
        if (distance < 100) {
          nearbyUsers.push({distance, id: userID})
        }
      }
    }

    // console.log('user range', USER_DISCOVER_RANGE)

    // if (users) {
    //   Object.keys(users).forEach(userID => {})
    // }

    dbRef.off('value')
    return nearbyUsers
  } catch (error) {
    console.error(error)
    throw error
  }
}

我在我的React Native应用程序中有这样的代码,它设置用户位置并查询附近的用户。问题是,当查询时,它第一次返回的数据不一致,它返回的数据少于它应该返回的数据,下一次它返回正确的结果后。
我尝试了geofire-js,但由于它不适用于'@react-native-firebase/database',由于大量的读取/写入,我也不能使用Firestore。

1zmg4dgp

1zmg4dgp1#

你在这里采取的方法不会起作用:

const latMin = center.latitude - latPerMeter * RADIUS
const latMax = center.latitude + latPerMeter * RADIUS
const lonMin = center.longitude - lonPerMeter * RADIUS
const lonMax = center.longitude + lonPerMeter * RADIUS

const dbRef = database()
  .ref('usersLocations')
  .orderByChild('g')
  .startAt(ngeohash.encode(latMin, lonMin))
  .endAt(ngeohash.encode(latMax, lonMax))

虽然彼此相似的geohash值可以保证彼此接近,但反之则不然:不能保证彼此接近的点将具有相似的Geohash值。
看看这个范围,例如:

虽然9r09r19r29r3在地理位置和字母顺序上都很接近,但9pp在地理位置上也很接近,但不是字母顺序。
因此,您需要为单个地理查询查询多个范围的geohash,最多9个iirc,但通常介于4和6之间。这就是为什么GeoFire库返回geohash边界列表的原因,您也可以在此代码片段中看到:https://firebase.google.com/docs/firestore/solutions/geoqueries#web_2
我的建议是查看geofire-common库的geohashQueryBounds函数,并从中复制您需要的内容。

相关问题