Flutter
...
Data Queries
Geoqueries
13 min
using flutter geolocation to perform geoqueries on parse introduction in this guide, you will learn about geopoint data type on parse and how to perform geo queries in parse using the flutter geolocation you will create an application that will perform geo queries and retrieve records using parse geopoints parse geopoints we won’t explain the flutter application code once this guide’s primary focus is on the flutter with parse prerequisites to complete this tutorial, you will need an app created on back4app note follow the new parse app tutorial to learn how to create a parse app on back4app an flutter app connected to back4app note follow the install parse sdk on flutter project to create an flutter project connected to back4app a device (or virtual device) running android or ios in order to run this guide example you should set up the plugin geolocator properly do not forget to add permissions for android and ios in order to access the device location { btn target=” blank” rel=”nofollow noreferer noopener”} in the project carefully read the instructions for setting up the android and ios project goal perform geoqueries using geopoints stored on back4app and flutter geolocation the geopoint datatype parse allows you to associate real world latitude and longitude coordinates with an object adding a parsegeopoint parsegeopoint to a parseobject parseobject will enable queries to consider the proximity of an object to a reference point this feature allows you to easily do things like finding out what user is closest to another user or which places are nearest to a user to associate a point with an object, you first need to create a parsegeopoint parsegeopoint below you can find a geopoint with a latitude of 40 0 degrees and 30 0 degrees longitude this point is then stored in the object as a regular field, like any other data type (string, number, date, etc ) note currently only one key in a class may be a parsegeopoint 1 the querybuilder class any parse query operation uses the querybuilder querybuilder object type, which will help you retrieve specific data from your database throughout your app to create a new querybuilder querybuilder , you need to pass as a parameter the desired parseobject parseobject subclass, which is the one that will contain your query results it is crucial to know that a querybuilder querybuilder will only resolve after calling a retrieve method query query , so a query can be set up and several modifiers can be chained before actually being called you can read more about the querybuilder querybuilder class here at the official documentation using the javascript console on back4app inside your back4app application’s dashboard, you will find a very useful api console in which you can run javascript code directly in this guide you will use to store data objects in back4app on your app main dashboard go to core >api console >javascript core >api console >javascript 2 save data on back4app to run the queries on this guide you’ll need first to populate your app with some data let’s create a city city class, which will be the target of our queries in this guide here is the parse object parse object classes creation code, so go ahead and run it in your api console 1 // add city objects and create table 2 // note how geopoints are created, passing latitude and longitude as arguments 3 // montevideo 4 city = new parse object('city'); 5 city set('name', 'montevideo uruguay'); 6 city set('location', new parse geopoint( 34 85553195363169, 56 207280375137955)); 7 await city save(); 8 9 // brasília 10 city = new parse object('city'); 11 city set('name', 'brasília brazil'); 12 city set('location', new parse geopoint( 15 79485821477289, 47 88391074690196)); 13 await city save(); 14 15 // bogotá 16 city = new parse object('city'); 17 city set('name', 'bogotá colombia'); 18 city set('location', new parse geopoint(4 69139880891712, 74 06936691331047)); 19 await city save(); 20 21 // mexico city 22 city = new parse object('city'); 23 city set('name', 'mexico city mexico'); 24 city set('location', new parse geopoint(19 400977162618933, 99 13311378164776)); 25 await city save(); 26 27 // washington, d c 28 city = new parse object('city'); 29 city set('name', 'washington, d c usa'); 30 city set('location', new parse geopoint(38 930727220189944, 77 04626261880388)); 31 await city save(); 32 33 // ottawa 34 city = new parse object('city'); 35 city set('name', 'ottawa canada'); 36 city set('location', new parse geopoint(45 41102167733425, 75 695414598736)); 37 await city save(); 38 39 // tokyo 40 city = new parse object('city'); 41 city set('name', 'tokyo japan'); 42 city set('location', new parse geopoint(35 6897, 139 6922)); 43 await city save(); 44 45 // mumbai 46 city = new parse object('city'); 47 city set('name', 'mumbai india'); 48 city set('location', new parse geopoint(18 9667, 72 8333)); 49 await city save(); 50 51 // shanghai 52 city = new parse object('city'); 53 city set('name', 'shanghai china'); 54 city set('location', new parse geopoint(31 1667, 121 4667)); 55 await city save(); 56 57 // new york 58 city = new parse object('city'); 59 city set('name', 'new york usa'); 60 city set('location', new parse geopoint(40 6943, 73 9249)); 61 await city save(); 62 63 // moscow 64 city = new parse object('city'); 65 city set('name', 'moscow russia'); 66 city set('location', new parse geopoint(55 7558, 37 6178)); 67 await city save(); 68 69 // paris 70 city = new parse object('city'); 71 city set('name', 'paris france'); 72 city set('location', new parse geopoint(48 8566, 2 3522)); 73 await city save(); 74 75 // paris 76 city = new parse object('city'); 77 city set('name', 'london united kingdom'); 78 city set('location', new parse geopoint(51 5072, 0 1275)); 79 await city save(); 80 81 // luanda 82 city = new parse object('city'); 83 city set('name', 'luanda angola'); 84 city set('location', new parse geopoint( 8 8383, 13 2344)); 85 await city save(); 86 87 // johannesburg 88 city = new parse object('city'); 89 city set('name', 'johannesburg south africa'); 90 city set('location', new parse geopoint( 26 2044, 28 0416)); 91 await city save(); 92 93 console log('success!'); after running this code, you should now have a city city class in your database your new class should look like this let’s now take a look at examples from every querybuilder querybuilder method, along with brief explanations on what they do 3 query the data now that you have a populated class, we can now perform some geopoint queries in it let’s begin by ordering city city results by the nearest from dallas in usa (latitude 32 779167, and longitude 96 808891), using the wherenear wherenear method 1 // create your query 2 final querybuilder\<parseobject> parsequery = 3 querybuilder\<parseobject>(parseobject('city')); 4 5 // create our geopoint for the query 6 final dallasgeopoint = 7 parsegeopoint(latitude 32 779167, longitude 96 808891); 8 9 // `wherenear` will order results based on distance between the geopoint 10 // type field from the class and the geopoint argument 11 parsequery wherenear('location', dallasgeopoint); 12 13 // the query will resolve only after calling this method, retrieving 14 // an array of `parseobjects`, if success 15 final parseresponse apiresponse = await parsequery query(); 16 17 if (apiresponse success && apiresponse results != null) { 18 // let's show the results 19 for (var o in apiresponse results! as list\<parseobject>) { 20 print( 21 'city ${o get\<string>('name')} location ${o get\<parsegeopoint>('location')! latitude}, ${o get\<parsegeopoint>('location')! longitude}'); 22 } 23 } let’s now query using the method wherewithinkilometers wherewithinkilometers , which will retrieve all results whose geopoint field is located within the max distance in kilometers dallas will be used once again as a reference and the distance limit will be 3000 km 1 // create your query 2 final querybuilder\<parseobject> parsequery = 3 querybuilder\<parseobject>(parseobject('city')); 4 5 // create our geopoint for the query 6 final dallasgeopoint = 7 parsegeopoint(latitude 32 779167, longitude 96 808891); 8 9 // you can also use `withinmiles` and `withinradians` the same way, 10 // but with different measuring unities 11 parsequery wherewithinkilometers('location', dallasgeopoint, 3000); 12 //parsequery wherewithinmiles('location', dallasgeopoint, 3000); 13 14 // the query will resolve only after calling this method, retrieving 15 // an array of `parseobjects`, if success 16 final parseresponse apiresponse = await parsequery query(); 17 18 if (apiresponse success && apiresponse results != null) { 19 // let's show the results 20 for (var o in apiresponse results! as list\<parseobject>) { 21 print( 22 'city ${o get\<string>('name')} location ${o get\<parsegeopoint>('location')! latitude}, ${o get\<parsegeopoint>('location')! longitude}'); 23 } 24 } let’s now query using the method wherewithinmiles wherewithinmiles , which will retrieve all results whose geopoint field is located within the max distance in miles dallas will be used once again as a reference and the distance limit will be 3000 miles 1 // create your query 2 final querybuilder\<parseobject> parsequery = 3 querybuilder\<parseobject>(parseobject('city')); 4 5 // create our geopoint for the query 6 final dallasgeopoint = 7 parsegeopoint(latitude 32 779167, longitude 96 808891); 8 9 // you can also use `wherewithinkilometers` and `wherewithinradians` the same way, 10 parsequery wherewithinmiles('location', dallasgeopoint, 3000); 11 12 // the query will resolve only after calling this method, retrieving 13 // an array of `parseobjects`, if success 14 final parseresponse apiresponse = await parsequery query(); 15 16 if (apiresponse success && apiresponse results != null) { 17 // let's show the results 18 for (var o in apiresponse results! as list\<parseobject>) { 19 print( 20 'city ${o get\<string>('name')} location ${o get\<parsegeopoint>('location')! latitude}, ${o get\<parsegeopoint>('location')! longitude}'); 21 } 22 } 4 query from flutter let’s now use our example queries inside a flutter app, with a simple interface having a list showing results and also 3 buttons for calling the queries the app also retrieves the device’s current location using geolocator plugin (follow the instructions), so the queries will be using real data open your flutter project, go to the main dart main dart file, clean up all the code, and replace it with 1 import 'package\ flutter/cupertino dart'; 2 import 'package\ flutter/material dart'; 3 import 'package\ geolocator/geolocator dart'; 4 import 'package\ parse server sdk flutter/parse server sdk dart'; 5 6 void main() async { 7 widgetsflutterbinding ensureinitialized(); 8 9 final keyapplicationid = 'your app id here'; 10 final keyclientkey = 'your client key here'; 11 12 final keyparseserverurl = 'https //parseapi back4app com'; 13 14 await parse() initialize(keyapplicationid, keyparseserverurl, 15 clientkey keyclientkey, debug true); 16 17 runapp(materialapp( 18 title 'flutter geopoint', 19 debugshowcheckedmodebanner false, 20 home homepage(), 21 )); 22 } 23 24 class homepage extends statefulwidget { 25 @override 26 homepagestate createstate() => homepagestate(); 27 } 28 29 class homepagestate extends state\<homepage> { 30 list\<parseobject> results = \<parseobject>\[]; 31 double selecteddistance = 3000; 32 33 future\<position> getcurrentposition() async { 34 bool serviceenabled; 35 locationpermission permission; 36 37 // test if location services are enabled 38 serviceenabled = await geolocator islocationserviceenabled(); 39 if (!serviceenabled) { 40 return future error('location services are disabled '); 41 } 42 43 permission = await geolocator checkpermission(); 44 if (permission == locationpermission denied) { 45 permission = await geolocator requestpermission(); 46 if (permission == locationpermission denied) { 47 return future error('location permissions are denied'); 48 } 49 } 50 51 if (permission == locationpermission deniedforever) { 52 return future error( 53 'location permissions are permanently denied, we cannot request permissions '); 54 } 55 56 // when we reach here, permissions are granted and we can 57 // continue accessing the position of the device 58 return await geolocator getcurrentposition(); 59 } 60 61 void doquerynear() async { 62 // create your query 63 final querybuilder\<parseobject> parsequery = 64 querybuilder\<parseobject>(parseobject('city')); 65 66 // get current position from device 67 final position = await getcurrentposition(); 68 69 final currentgeopoint = parsegeopoint( 70 latitude position latitude, longitude position longitude); 71 72 // `wherenear` will order results based on distance between the geopoint 73 // type field from the class and the geopoint argument 74 parsequery wherenear('location', currentgeopoint); 75 76 // the query will resolve only after calling this method, retrieving 77 // an array of `parseobjects`, if success 78 final parseresponse apiresponse = await parsequery query(); 79 80 if (apiresponse success && apiresponse results != null) { 81 // let's show the results 82 for (var o in apiresponse results! as list\<parseobject>) { 83 print( 84 'city ${o get\<string>('name')} location ${o get\<parsegeopoint>('location')! latitude}, ${o get\<parsegeopoint>('location')! longitude}'); 85 } 86 87 setstate(() { 88 results = apiresponse results as list\<parseobject>; 89 }); 90 } else { 91 setstate(() { 92 results clear(); 93 }); 94 } 95 } 96 97 void doqueryinkilometers() async { 98 // create your query 99 final querybuilder\<parseobject> parsequery = 100 querybuilder\<parseobject>(parseobject('city')); 101 102 // get current position from device 103 final position = await getcurrentposition(); 104 105 final currentgeopoint = parsegeopoint( 106 latitude position latitude, longitude position longitude); 107 108 // you can also use `wherewithinmiles` and `wherewithinradians` the same way, 109 // but with different measuring unities 110 parsequery wherewithinkilometers( 111 'location', currentgeopoint, selecteddistance); 112 113 // the query will resolve only after calling this method, retrieving 114 // an array of `parseobjects`, if success 115 final parseresponse apiresponse = await parsequery query(); 116 117 if (apiresponse success && apiresponse results != null) { 118 // let's show the results 119 for (var o in apiresponse results! as list\<parseobject>) { 120 print( 121 'city ${o get\<string>('name')} location ${o get\<parsegeopoint>('location')! latitude}, ${o get\<parsegeopoint>('location')! longitude}'); 122 } 123 124 setstate(() { 125 results = apiresponse results as list\<parseobject>; 126 }); 127 } else { 128 setstate(() { 129 results clear(); 130 }); 131 } 132 } 133 134 void doqueryinmiles() async { 135 // create your query 136 final querybuilder\<parseobject> parsequery = 137 querybuilder\<parseobject>(parseobject('city')); 138 139 // get current position from device 140 final position = await getcurrentposition(); 141 142 final currentgeopoint = parsegeopoint( 143 latitude position latitude, longitude position longitude); 144 145 // you can also use `wherewithinkilometers` and `wherewithinradians` the same way, 146 parsequery wherewithinmiles('location', currentgeopoint, selecteddistance); 147 148 // the query will resolve only after calling this method, retrieving 149 // an array of `parseobjects`, if success 150 final parseresponse apiresponse = await parsequery query(); 151 152 if (apiresponse success && apiresponse results != null) { 153 // let's show the results 154 for (var o in apiresponse results! as list\<parseobject>) { 155 print( 156 'city ${o get\<string>('name')} location ${o get\<parsegeopoint>('location')! latitude}, ${o get\<parsegeopoint>('location')! longitude}'); 157 } 158 159 setstate(() { 160 results = apiresponse results as list\<parseobject>; 161 }); 162 } else { 163 setstate(() { 164 results clear(); 165 }); 166 } 167 } 168 169 void doclearresults() async { 170 setstate(() { 171 results = \[]; 172 }); 173 } 174 175 @override 176 widget build(buildcontext context) { 177 return scaffold( 178 body padding( 179 padding const edgeinsets all(16 0), 180 child column( 181 crossaxisalignment crossaxisalignment stretch, 182 children \[ 183 container( 184 height 200, 185 child image network( 186 'https //blog back4app com/wp content/uploads/2017/11/logo b4a 1 768x175 1 png'), 187 ), 188 center( 189 child const text('flutter on back4app geopoint', 190 style textstyle(fontsize 18, fontweight fontweight bold)), 191 ), 192 sizedbox( 193 height 8, 194 ), 195 container( 196 height 50, 197 child elevatedbutton( 198 onpressed doquerynear, 199 child text('query near'), 200 style elevatedbutton stylefrom(primary colors blue)), 201 ), 202 sizedbox( 203 height 16, 204 ), 205 center(child text('distance')), 206 slider( 207 value selecteddistance, 208 min 0, 209 max 10000, 210 divisions 10, 211 onchanged (value) { 212 setstate(() { 213 selecteddistance = value; 214 }); 215 }, 216 label selecteddistance tostringasfixed(0), 217 ), 218 sizedbox( 219 height 8, 220 ), 221 container( 222 height 50, 223 child elevatedbutton( 224 onpressed doqueryinkilometers, 225 child text('query in kilometers'), 226 style elevatedbutton stylefrom(primary colors blue)), 227 ), 228 sizedbox( 229 height 8, 230 ), 231 container( 232 height 50, 233 child elevatedbutton( 234 onpressed doqueryinmiles, 235 child text('query miles'), 236 style elevatedbutton stylefrom(primary colors blue)), 237 ), 238 sizedbox( 239 height 8, 240 ), 241 container( 242 height 50, 243 child elevatedbutton( 244 onpressed doclearresults, 245 child text('clear results'), 246 style elevatedbutton stylefrom(primary colors blue)), 247 ), 248 sizedbox( 249 height 8, 250 ), 251 text( 252 'result list ${results length}', 253 ), 254 expanded( 255 child listview\ builder( 256 itemcount results length, 257 itembuilder (context, index) { 258 final o = results\[index]; 259 return container( 260 padding const edgeinsets all(4), 261 decoration 262 boxdecoration(border border all(color colors black)), 263 child text( 264 '${o get\<string>('name')} \nlocation ${o get\<parsegeopoint>('location')! latitude}, ${o get\<parsegeopoint>('location')! longitude}'), 265 ); 266 }), 267 ) 268 ], 269 ), 270 )); 271 } 272 } find your application id and client key credentials navigating to your app dashboard at back4app website https //www back4app com/ update your code in main dart main dart with the values of your project’s applicationid and clientkey in back4app keyapplicationid = app id keyclientkey = client key run the project, and the app will load as shown in the image conclusion at the end of this guide, you learned how geopoint data queries work on parse and how to perform them on back4app from a flutter app