In another article, we wrote about how to save Backendless data objects with related geopoint(s). The data-to-geo relations are bidirectional. That means that just as a data object can reference a geopoint (or more than one) as a relation, a geopoint may reference a data object or a collection of in its metadata as well.
Consider the example below. The code saves a geopoint which represents the Eiffel Tower. The geopoint references a data object which represents the tower’s main engineer, Gustavo Eiffel, saved in the Architect table. Notice the “gustavoEiffel” object is a plain Java object (a POJO) which is saved in the Data Service storage in Backendless. The relation between the geopoint and the data object is handled through the geopoint’s metadata:
Architect gustaveEiffel = new Architect(); gustaveEiffel.setName("Gustave Eiffel"); Calendar calendar = Calendar.getInstance(); calendar.set(1923, 11, 27); gustaveEiffel.setBirthday(calendar.getTime()); gustaveEiffel.setNationality("French"); Backendless.Data.of(Architect.class).save(gustaveEiffel, new AsyncCallback<Architect>() { @Override public void handleResponse(Architect savedArchitect) { GeoPoint eiffelTower = new GeoPoint(48.85815, 2.29452); eiffelTower.addCategory("towers"); eiffelTower.addCategory("placesToVisit"); eiffelTower.addMetadata("name", "Eiffel Tower"); eiffelTower.addMetadata("architect", savedArchitect); Backendless.Geo.savePoint(eiffelTower, new AsyncCallback<GeoPoint>() { @Override public void handleResponse(GeoPoint geoPoint) { Log.i(TAG, "Geo point has been saved - " + geoPoint.getObjectId()); } @Override public void handleFault(BackendlessFault fault) { Log.i(TAG, fault.getMessage()); } }); } @Override public void handleFault(BackendlessFault fault) { Log.e(TAG, fault.getMessage()); } });
val gustaveEiffel = Architect() gustaveEiffel.name = "Gustave Eiffel" val calendar = Calendar.getInstance() calendar.set(1923, 11, 27) gustaveEiffel.birthday = calendar.time gustaveEiffel.nationality = "French" Backendless.Data.of(Architect::class.java).save(gustaveEiffel, object : AsyncCallback<Architect> { override fun handleResponse(savedArchitect: Architect) { val eiffelTower = GeoPoint(48.85815, 2.29452) eiffelTower.addCategory("towers") eiffelTower.addCategory("placesToVisit") eiffelTower.addMetadata("name", "Eiffel Tower") eiffelTower.addMetadata("architect", savedArchitect) Backendless.Geo.savePoint(eiffelTower, object : AsyncCallback<GeoPoint> { override fun handleResponse(geoPoint: GeoPoint) { Log.i(TAG, "Geo point has been saved - ${geoPoint.objectId}") } override fun handleFault(fault: BackendlessFault) { Log.i(TAG, fault.message) } }) } override fun handleFault(fault: BackendlessFault) { Log.e(TAG, fault.message) } })
NSString *birthdateString = @"15/12/1832"; NSDateFormatter *dateFormatter = [NSDateFormatter new]; dateFormatter.dateFormat = @"dd/MM/yyyy"; Architect *gustaveEiffel = [Architect new]; gustaveEiffel.name = @"Gustave Eiffel"; gustaveEiffel.nationality = @"French"; gustaveEiffel.birthdate = [dateFormatter dateFromString:birthdateString]; [[Backendless.shared.data of:[Architect class]] saveWithEntity:gustaveEiffel responseHandler:^(Architect * savedArchitect) { NSDictionary *metadata = @{@"name": @"Eiffel Tower", @"architect": savedArchitect}; GeoPoint *eiffelTower = [[GeoPoint alloc] initWithLatitude:48.85815 longitude:2.29452 categories:@[@"towers", @"placesToVisit"] metadata:metadata]; [Backendless.shared.geo saveGeoPointWithGeoPoint:eiffelTower responseHandler:^(GeoPoint *savedPoint) { NSLog(@"Geo point has been saved - %@", savedPoint.objectId); } errorHandler:^(Fault *fault) { NSLog(@"Error: %@", fault.message); }]; } errorHandler:^(Fault *fault) { NSLog(@"Error: %@", fault.message); }];
let birthdateString = "15/12/1832" let dateFormatter = DateFormatter() dateFormatter.dateFormat = "dd/MM/yyyy" let gustaveEiffel = Architect() gustaveEiffel.name = "Gustave Eiffel" gustaveEiffel.nationality = "French" gustaveEiffel.birthdate = dateFormatter.date(from: birthdateString) Backendless.shared.data.of(Architect.self).save(entity: gustaveEiffel, responseHandler: { savedArchitect in let metadata = ["name": "Eiffel Tower", "architect": savedArchitect] let eiffelTower = GeoPoint(latitude: 48.85815, longitude: 2.29452, categories: ["towers", "placesToVisit"], metadata: metadata) Backendless.shared.geo.saveGeoPoint(geoPoint: eiffelTower, responseHandler: { savedPoint in print("Geo point has been saved - \(savedPoint.objectId ?? "")") }, 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 saveArchitect = async () => { const architect = new Architect() architect.setName('Gustave Eiffel') architect.setBirthday(new Date('05/12/1980').getTime()) architect.setNationality('French') const eiffelTower = new Backendless.GeoPoint() eiffelTower.latitude = 48.85815 eiffelTower.longitude = 2.29452 eiffelTower.categories = ['towers', 'placesToVisit'] eiffelTower.metadata = { name : 'Eiffel Tower', architect: architect } const savedPoint = await Backendless.Geo.savePoint(eiffelTower) console.log(`Geo point has been saved - ${ savedPoint.objectId }`) } 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(saveArchitect) .catch(onError)
Map gustaveEiffel = { "name": "Gustave Eiffel", "birthday": DateTime(1923, 11, 27), "nationality": "French" }; Backendless.Data.of("Architect").save(gustaveEiffel).then((savedArchitect) { GeoPoint eiffelTower = GeoPoint.fromLatLng(48.85815, 2.29452); eiffelTower.categories = ["towers", "placesToVisit"]; eiffelTower.metadata = {"name": "Eiffel Tower", "architect": savedArchitect}; Backendless.Geo.savePoint(eiffelTower).then( (geoPoint) => print("Geo point has been saved - ${geoPoint.objectId}")); });
The Architect class:
public class Architect { private String nationality; private String name; private Date birthday; private String objectId; public void setName(String name) { this.name = name; } public String getName() { return name; } public void setBirthday(Date birthday) { this.birthday = birthday; } public Date getBirthday() { return birthday; } public void setNationality(String nationality) { this.nationality = nationality; } public String getNationality() { return nationality; } public String getObjectId() { return objectId; } public void setObjectId(String objectId) { this.objectId = objectId; } }
import java.util.Date data class Architect(var objectId: String? = null, var birthday: Date? = null, var name: String? = null, var nationality: String? = null)
@interface Architect : NSObject @property (strong, nonatomic) NSString *name; @property (strong, nonatomic) NSString *nationality; @property (strong, nonatomic) NSDate *birthdate; @end
@objcMembers class Architect: NSObject { var name: String? var nationality: String? var birthdate: Date? }
function Architect() { let nationality = '' let name = '' let birthday this.___class = 'Architect' this.setName = function (name) { this.name = name return this } this.getName = function () { return this.name } this.setBirthday = function (birthday) { this.birthday = birthday return this } this.getBirthdat = function () { return this.birthday } this.setNationality = function (nationality) { this.nationality = nationality return this } this.getNationality = function () { return this.nationality } }
The Backendless SDK for Flutter uses the map/dictionary-based approach for data persistence.
Once you run the code and open the Geolocation screen in Backendless Console, you will see the following:
If you click the Architect object link in the geopoint’s metadata column, the Console displays the following popup which makes it very easy to see the related data object:
Alternatively, if you navigate to the Data screen and select the Architect table, it will show the saved data object:
Enjoy!