Blog

How to Retrieve Geopoints for a Category

by on September 1, 2019

In the introductory post, we gave a brief description of the Backendless Geolocation service and wrote how to setup sample geodata. Now that we have a collection of geopoints, let’s look into the API to retrieve these points. Similar to data objects, Backendless returns geopoints using paged data.

Consider the following sample code:

       final BackendlessGeoQuery geoQuery = new BackendlessGeoQuery();
       geoQuery.addCategory("geoservice_sample");
       geoQuery.setIncludeMeta(true);
    
       Backendless.Geo.getGeopointCount(geoQuery, new AsyncCallback<Integer>() {
           @Override
           public void handleResponse(Integer count) {
               Log.i(TAG, "Total points in category " + count);
    
               Backendless.Geo.getPoints(geoQuery, new AsyncCallback<List<GeoPoint>>() {
    
                   @Override
                   public void handleResponse(List<GeoPoint> points) {
                       for (GeoPoint geoPoint : points) {
                           Log.i(TAG, "GeoPoint: latitude - " + geoPoint.getLatitude() +
                               ", longitude - " + geoPoint.getLongitude());
                           Log.i(TAG, "\tmetadata: ");
    
                           for (Map.Entry entry : geoPoint.getMetadata().entrySet())
                               Log.i(TAG, "\t\t" + entry.getKey() + " - " + entry.getValue());
                       }
                      
                       if (points.size() == geoQuery.getPageSize()) {
                           geoQuery.prepareForNextPage();
                           Backendless.Geo.getPoints(geoQuery, this);
                       }
                   }
    
                   @Override
                   public void handleFault(BackendlessFault fault) {
                       Log.e(TAG, fault.getMessage());
                   }
               });
           }
    
           @Override
           public void handleFault(BackendlessFault fault) {
               Log.e(TAG, fault.getMessage());
           }
       });
    

       val geoQuery = BackendlessGeoQuery()
       geoQuery.addCategory("geoservice_sample")
       geoQuery.isIncludeMeta = true
    
       Backendless.Geo.getGeopointCount(geoQuery, object : AsyncCallback<Int> {
           override fun handleResponse(count: Int?) {
               Log.i(TAG, "Total points in category $count")
    
               Backendless.Geo.getPoints(geoQuery, object : AsyncCallback<List<GeoPoint>> {
    
                   override fun handleResponse(points: List<GeoPoint>) {
                       for (geoPoint in points) {
                           Log.i(TAG, "GeoPoint: latitude - ${geoPoint.latitude}, longitude - ${geoPoint.longitude}")
                           Log.i(TAG, "\tmetadata: ")
    
                           for ((key, value) in geoPoint.metadata)
                               Log.i(TAG, "\t\t$key - $value")
                       }
    
                       if (points.size == geoQuery.pageSize) {
                           geoQuery.prepareForNextPage()
                           Backendless.Geo.getPoints(geoQuery, this)
                       }
                   }
    
                   override fun handleFault(fault: BackendlessFault) {
                       Log.e(TAG, fault.message)
                   }
               })
           }
    
           override fun handleFault(fault: BackendlessFault) {
               Log.e(TAG, fault.message)
           }
       })
    

    __block BOOL firstResponse = YES;
    BackendlessGeoQuery *geoQuery = [BackendlessGeoQuery new];
    geoQuery.categories = @[@"geoservice_sample"];
    geoQuery.includemetadata = YES;
    
    - (void)loadGeoPoints {
        [Backendless.shared.geo getPointsWithGeoQuery:geoQuery responseHandler:^(NSArray *points) {
            [Backendless.shared.geo getPointsCountWithGeoQuery:self->geoQuery responseHandler:^(NSInteger totalPoints) {
                if (self->firstResponse) {
                    self->firstResponse = NO;
                    NSLog(@"Total points in category %li", (long)totalPoints);
                }
                if (points.count > 0) {
                    for (GeoPoint *point in points) {
                        NSLog(@"GeoPoint: latitude - %f, longitude - %f", point.latitude, point.longitude);
                        NSLog(@"\tmetadata:");
                        for (NSString *key in point.metadata.allKeys) {
                            NSLog(@"\t\t%@ - %@", key, [point.metadata valueForKey:key]);
                        }
                    }
                }
                if (self->geoQuery.offset < totalPoints) { [self->geoQuery prepareNextPage];
                    [self loadGeoPoints];
                }
            } errorHandler:^(Fault *fault) {
                NSLog(@"Error: %@", fault.message);
            }];
        } errorHandler:^(Fault *fault) {
            NSLog(@"Error: %@", fault.message);
        }];
    }

    var firstResponse = true
    var geoQuery = BackendlessGeoQuery()
    geoQuery.categories = ["geoservice_sample"]
    geoQuery.includemetadata = true
    
    func loadGeoPoints() {
        Backendless.shared.geo.getPoints(geoQuery: geoQuery, responseHandler: { points in
            Backendless.shared.geo.getPointsCount(geoQuery: self.geoQuery, responseHandler: { totalPoints in
                if self.firstResponse {
                    self.firstResponse = false
                    print("Total points in category \(totalPoints)")
                }
                if points.count > 0 {
                    for point in points {
                        print("GeoPoint: latitude - \(point.latitude), longitude - \(point.longitude)")
                        if let metadata = point.metadata {
                            print("\tmetadata:")
                            for key in Array(metadata.keys) {
                                print("\t\t\(key) - \(metadata[key] ?? "")")
                            }
                        }
                    }
                }
                if self.geoQuery.offset < totalPoints {
                    self.geoQuery.prepareNextPage()
                    self.loadGeoPoints()
                }
            }, errorHandler: { fault in
                print("Error: \(fault.message ?? "")")
            })
        }, errorHandler: { fault in
            print("Error: \(fault.message ?? "")")
        })
    }

    const Backendless = require('backendless')
    /*
     Or use `import Backendless from 'backendless'` for client side.
     If you don't use npm or yarn to install modules, you can add the following line
     <script src="//api.backendless.com/sdk/js/latest/backendless.min.js"></script>
     to your index.html file and use the global Backendless variable.
    */
    
    Backendless.initApp('YOUR_APP_ID', 'YOUR_JS_API_KEY')
    
    const PAGE_SIZE = 100 // max allowed value
    
    const loadGeoPoints = async () => {
      let offset = 0
      let totalCount = 0
      let lastPageSize = 0
      const itemsCollection = []
    
      do {
        const pageQuery = new Backendless.GeoQuery()
    
        pageQuery.categories = ['geoservice_sample']
        pageQuery.includemetadata = true
        pageQuery.pageSize = PAGE_SIZE
        pageQuery.offset = offset
    
        const items = await Backendless.Geo.find(pageQuery)
    
        lastPageSize = items.length
    
        itemsCollection.push(...items)
    
        offset += PAGE_SIZE
        totalCount += lastPageSize
      } while (lastPageSize >= PAGE_SIZE)
    
      return itemsCollection
    }
    
    const onSuccess = points => {
      console.log(`Total points in category ${ points.length }`)
    
      points.forEach(point => {
        console.log(`GeoPoint: latitude - ${ point.latitude }, longitude - ${ point.longitude }`)
        console.log('Metadata:')
    
        for (let field in point.metadata) {
          console.log(`${ field } - ${ point.metadata[field] }`)
        }
    
        console.log()
      })
    }
    
    const onError = error => {
      console.error('Server reported an error: ', error.message)
      console.error('error code: ', error.code)
      console.error('http status: ', error.status)
    }
    
    Promise.resolve()
      .then(loadGeoPoints)
      .then(onSuccess)
      .catch(onError)
    

       BackendlessGeoQuery geoQuery = BackendlessGeoQuery()
         ..addCategory("geoservice_sample")
         ..includeMeta = true;
    
         Function getPoints;
         getPoints = () {
           Backendless.Geo.getPoints(query: geoQuery).then((points) {
             points.forEach((geoPoint) {
               print("GeoPoint: latitude - ${geoPoint.latitude}, longitude - ${geoPoint.longitude}");
               print("\tmetadata: ");
    
               geoPoint.metadata.forEach((key, value) => print("\t\t$key - $value"));
             });
    
             if (points.length == geoQuery.pageSize) {
               geoQuery.prepareNextPage();
               getPoints();
             }
           });
         };
    
         Backendless.Geo.getGeopointCount(geoQuery).then((count) {
           print("Total points in category $count");
           getPoints();
         });
    


    The API relies on creating a query object which identifies the category from which the geopoints should be loaded. Additionally, a flag is set requesting the server to return metadata for every geopoint (the metadata is not returned by default).

    The code produces the following output (reduced for brevity since there are 332 points in the sample data set).

    Total points in category 332
    GeoPoint: latitude - -37.814, longitude - 144.96332
    	metadata:
    		city - MELBOURNE
    GeoPoint: latitude - -34.93333, longitude - 138.6
    	metadata:
    		city - ADELAIDE
    GeoPoint: latitude - -33.86785, longitude - 151.20732
    	metadata:
    		city - SYDNEY
    GeoPoint: latitude - -31.93333, longitude - 115.83333
    	metadata:
    		city - PERTH
    GeoPoint: latitude - -27.48333, longitude - 153.01667
    	metadata:
    		city - SOUTH BRISBANE
    ....

    Enjoy!

    Leave a Reply