2017-10-08 16 views
9

क्या फ़ायरबेस से नया फायरस्टोर डेटाबेस मूल रूप से स्थान आधारित भौगोलिक प्रश्नों का समर्थन करता है? यानी 10 मील के भीतर पोस्ट खोजें, या 50 निकटतम पोस्ट खोजें?फायरस्टोर के साथ भौगोलिक "पास" क्वेरी कैसे चलाएं?

मुझे लगता है कि रीयल-टाइम फायरबेस डेटाबेस के लिए कुछ मौजूदा परियोजनाएं हैं, भूगर्भ जैसी परियोजनाएं- क्या उन्हें फायरस्टोर में भी अनुकूलित किया जा सकता है?

+4

संभावित डुप्लिकेट [फायरबेस क्लाउड फायरस्टोर में संग्रह में निकटतम जियोपॉइंट्स से पूछताछ कैसे करें?] (Https://stackoverflow.com/questions/46607760/how-to-query-closest-geopoints-in-a-collection -इन-firebase-क्लाउड-firestore) –

उत्तर

3

आज तक, ऐसी कोई क्वेरी करने का कोई तरीका नहीं है। वहाँ यह करने के लिए इतना संबंधित में अन्य प्रश्न हैं:

Is there a way to use GeoFire with Firestore?

How to query closest GeoPoints in a collection in Firebase Cloud Firestore?

Is there a way to use GeoFire with Firestore?

मेरे वर्तमान एंड्रॉयड परियोजना में मैं https://github.com/drfonfon/android-geohash उपयोग कर सकते हैं एक geohash क्षेत्र को जोड़ने के लिए है, जबकि Firebase टीम देशी समर्थन विकासशील है ।

अन्य प्रश्नों में सुझाए गए फायरबेस रीयलटाइम डेटाबेस का उपयोग करना मतलब है कि आप अपने परिणामों को स्थान और अन्य क्षेत्रों द्वारा सेट किए गए फ़िल्टर को फ़िल्टर नहीं कर सकते हैं, मुख्य कारण मैं पहली बार फायरस्टोर पर स्विच करना चाहता हूं।

14

यह क्वेरी से अधिक से अधिक बाध्यकारी बॉक्स बनाकर किया जा सकता है। दक्षता के लिए, मैं इससे बात नहीं कर सकता।

ध्यान दें, की सटीकता अक्षांश/देशांतर ऑफसेट के लिए ~ 1 मील समीक्षा की जानी चाहिए, लेकिन यहाँ एक त्वरित तरीका है यह करने के लिए है:

स्विफ्ट 3.0 संस्करण

func getDocumentNearBy(latitude: Double, longitude: Double, distance: Double) { 

    // ~1 mile of lat and lon in degrees 
    let lat = 0.0144927536231884 
    let lon = 0.0181818181818182 

    let lowerLat = latitude - (lat * distance) 
    let lowerLon = longitude - (lon * distance) 

    let greaterLat = latitude + (lat * distance) 
    let greaterLon = longitude + (lon * distance) 

    let lesserGeopoint = GeoPoint(latitude: lowerLat, longitude: lowerLon) 
    let greaterGeopoint = GeoPoint(latitude: greaterLat, longitude: greaterLon) 

    let docRef = Firestore.firestore().collection("locations") 
    let query = docRef.whereField("location", isGreaterThan: lesserGeopoint).whereField("location", isLessThan: greaterGeopoint) 

    query.getDocuments { snapshot, error in 
     if let error = error { 
      print("Error getting documents: \(error)") 
     } else { 
      for document in snapshot!.documents { 
       print("\(document.documentID) => \(document.data())") 
      } 
     } 
    } 

} 

func run() { 
    // Get all locations within 10 miles of Google Headquarters 
    getDocumentNearBy(latitude: 37.422000, longitude: -122.084057, distance: 10) 
} 
6

(पहले मुझे इस पोस्ट में सभी कोड के लिए माफ़ी मांगना है, मैं चाहता हूं कि कोई भी इस जवाब को कार्यक्षमता को पुन: उत्पन्न करने में आसान समय प्राप्त करे।)

उसी चिंता को हल करने के लिए ओपी ने पहले,को अनुकूलित किया था फायरस्टोर के साथ काम करने के लिए 10 (आप उस पुस्तकालय को देखकर भू-सामान के बारे में बहुत कुछ सीख सकते हैं)। तब मुझे एहसास हुआ कि अगर वास्तव में एक सटीक सर्कल में स्थान लौटाया गया तो मुझे वास्तव में कोई फर्क नहीं पड़ता। मैं बस 'आस-पास' स्थानों को पाने का कोई तरीका चाहता था।

मुझे विश्वास नहीं है कि मुझे यह समझने में कितना समय लगेगा, लेकिन आप एक केंद्र बिंदु के चारों ओर एक बाउंडिंग बॉक्स के भीतर स्थानों को प्राप्त करने के लिए एक एसडब्ल्यू कोने और एनई कोने का उपयोग करके एक भू-बिंदु फ़ील्ड पर डबल असमानता क्वेरी कर सकते हैं।

इसलिए मैंने नीचे एक जैसा जावास्क्रिप्ट फ़ंक्शन बनाया (यह मूल रूप से रयान ली के उत्तर का जेएस संस्करण है)।

/** 
* Get locations within a bounding box defined by a center point and distance from from the center point to the side of the box; 
* 
* @param {Object} area an object that represents the bounding box 
* around a point in which locations should be retrieved 
* @param {Object} area.center an object containing the latitude and 
* longitude of the center point of the bounding box 
* @param {number} area.center.latitude the latitude of the center point 
* @param {number} area.center.longitude the longitude of the center point 
* @param {number} area.radius (in kilometers) the radius of a circle 
* that is inscribed in the bounding box; 
* This could also be described as half of the bounding box's side length. 
* @return {Promise} a Promise that fulfills with an array of all the 
* retrieved locations 
*/ 
function getLocations(area) { 
    // calculate the SW and NE corners of the bounding box to query for 
    const box = utils.boundingBoxCoordinates(area.center, area.radius); 

    // construct the GeoPoints 
    const lesserGeopoint = new GeoPoint(box.swCorner.latitude, box.swCorner.longitude); 
    const greaterGeopoint = new GeoPoint(box.neCorner.latitude, box.neCorner.longitude); 

    // construct the Firestore query 
    let query = firebase.firestore().collection('myCollection').where('location', '>', lesserGeopoint).where('location', '<', greaterGeopoint); 

    // return a Promise that fulfills with the locations 
    return query.get() 
    .then((snapshot) => { 
     const allLocs = []; // used to hold all the loc data 
     snapshot.forEach((loc) => { 
     // get the data 
     const data = loc.data(); 
     // calculate a distance from the center 
     data.distanceFromCenter = utils.distance(area.center, data.location); 
     // add to the array 
     allLocs.push(data); 
     }); 
     return allLocs; 
    }) 
    .catch((err) => { 
     return new Error('Error while retrieving events'); 
    }); 
} 

समारोह ऊपर भी स्थान डेटा के प्रत्येक टुकड़े कि इतना है कि तुम सिर्फ अगर उस दूरी रेंज आप चाहते हैं के भीतर है की जाँच करके चक्र की तरह व्यवहार मिल सकता है वापस आ रहा है करने के लिए एक .distanceFromCenter संपत्ति कहते हैं।

मैं ऊपर दिए गए फ़ंक्शन में दो उपयोग फ़ंक्शंस का उपयोग करता हूं, इसलिए यहां उन लोगों के लिए कोड भी है। (नीचे दिए गए सभी उपयोग कार्यों को वास्तव में जियोफायर लाइब्रेरी से अनुकूलित किया जाता है।)

दूरी():

/** 
* Calculates the distance, in kilometers, between two locations, via the 
* Haversine formula. Note that this is approximate due to the fact that 
* the Earth's radius varies between 6356.752 km and 6378.137 km. 
* 
* @param {Object} location1 The first location given as .latitude and .longitude 
* @param {Object} location2 The second location given as .latitude and .longitude 
* @return {number} The distance, in kilometers, between the inputted locations. 
*/ 
distance(location1, location2) { 
    const radius = 6371; // Earth's radius in kilometers 
    const latDelta = degreesToRadians(location2.latitude - location1.latitude); 
    const lonDelta = degreesToRadians(location2.longitude - location1.longitude); 

    const a = (Math.sin(latDelta/2) * Math.sin(latDelta/2)) + 
      (Math.cos(degreesToRadians(location1.latitude)) * Math.cos(degreesToRadians(location2.latitude)) * 
      Math.sin(lonDelta/2) * Math.sin(lonDelta/2)); 

    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); 

    return radius * c; 
} 

boundingBoxCoordinates(): (अधिक यहाँ भी में प्रयोग किया जाता utils कि मैं नीचे चिपकाया है कर रहे हैं)

/** 
* Calculates the SW and NE corners of a bounding box around a center point for a given radius; 
* 
* @param {Object} center The center given as .latitude and .longitude 
* @param {number} radius The radius of the box (in kilometers) 
* @return {Object} The SW and NE corners given as .swCorner and .neCorner 
*/ 
boundingBoxCoordinates(center, radius) { 
    const KM_PER_DEGREE_LATITUDE = 110.574; 
    const latDegrees = radius/KM_PER_DEGREE_LATITUDE; 
    const latitudeNorth = Math.min(90, center.latitude + latDegrees); 
    const latitudeSouth = Math.max(-90, center.latitude - latDegrees); 
    // calculate longitude based on current latitude 
    const longDegsNorth = metersToLongitudeDegrees(radius, latitudeNorth); 
    const longDegsSouth = metersToLongitudeDegrees(radius, latitudeSouth); 
    const longDegs = Math.max(longDegsNorth, longDegsSouth); 
    return { 
    swCorner: { // bottom-left (SW corner) 
     latitude: latitudeSouth, 
     longitude: wrapLongitude(center.longitude - longDegs), 
    }, 
    neCorner: { // top-right (NE corner) 
     latitude: latitudeNorth, 
     longitude: wrapLongitude(center.longitude + longDegs), 
    }, 
    }; 
} 

metersToLongitudeDegrees():।

/** 
* Calculates the number of degrees a given distance is at a given latitude. 
* 
* @param {number} distance The distance to convert. 
* @param {number} latitude The latitude at which to calculate. 
* @return {number} The number of degrees the distance corresponds to. 
*/ 
function metersToLongitudeDegrees(distance, latitude) { 
    const EARTH_EQ_RADIUS = 6378137.0; 
    // this is a super, fancy magic number that the GeoFire lib can explain (maybe) 
    const E2 = 0.00669447819799; 
    const EPSILON = 1e-12; 
    const radians = degreesToRadians(latitude); 
    const num = Math.cos(radians) * EARTH_EQ_RADIUS * Math.PI/180; 
    const denom = 1/Math.sqrt(1 - E2 * Math.sin(radians) * Math.sin(radians)); 
    const deltaDeg = num * denom; 
    if (deltaDeg < EPSILON) { 
    return distance > 0 ? 360 : 0; 
    } 
    // else 
    return Math.min(360, distance/deltaDeg); 
} 

wrapLongitude():

/** 
* Wraps the longitude to [-180,180]. 
* 
* @param {number} longitude The longitude to wrap. 
* @return {number} longitude The resulting longitude. 
*/ 
function wrapLongitude(longitude) { 
    if (longitude <= 180 && longitude >= -180) { 
    return longitude; 
    } 
    const adjusted = longitude + 180; 
    if (adjusted > 0) { 
    return (adjusted % 360) - 180; 
    } 
    // else 
    return 180 - (-adjusted % 360); 
} 
संबंधित मुद्दे