Support Topics Documentation Slack YouTube Blog

Linking a specific record to a specific geopoint


(Ben Foster) #1

Hi all,

I am trying to relate records from my table to a specific geopoint, using a one-to-one relationship.

I am currently relating my geopoints to the data by passing the ‘saved record’ to the geopoints metadata:

function savedMeeting(savedMeeting) {
console.log(savedMeeting);
// Relate geopoint to specific meeting using meta data
appointmentLocation.metadata = {"Meetings": savedMeeting};
//Add geopoint to Backendless Meetings database
var geopoint = Backendless.Geo.savePoint(savedMeeting);

// Process new added meeting
Backendless.Data.of("Meetings").find().then(processResults).catch(error);
}

This successfully links the geopoint to the meeting:

However I need this relationship the other way round; the data relating to the geopoint in order to retrieve the latitude and longitude at a later time. I am currently trying to do so by adding the geopoint location to the Backendless save data object:

function addMeeting() {
// Name
appointmentName = $('#formName').val();
// Time
var dtp = $('#formTime').val();
appointmentTime = new Date(dtp);
// Location
var geopoint = Backendless.Geo.savePoint(appointmentLocation);

var newMeeting = {};
newMeeting.Appointment = appointmentName;
newMeeting.Time = appointmentTime;
newMeeting.Location = geopoint;

//Save meetings object to Backendless database
if((appointmentName !== "") && (appointmentTime !== "")) {
    Backendless.Data.of("Meetings").save(newMeeting).then(savedMeeting).catch(error);
    }
}

The ‘geopoint’ is successfully passing the latitude and longitude from the ‘appointmentLocation’ object, however this geopoint is still not saved within the ‘Location’ column of the Meetings table, which is left empty.

I have followed the documentation for relating data objects to geopoints, and have also tried custom classes as suggested within the documentation - any suggestions as to solving this problem would be greatly appreciated.


(Vladimir Upirov) #2

Hi Ben

There is wrong code sample, for setting/adding Data/Geo relations you have to use setRelation/addRelation methods

Backendless.Data.of( "Meetings" ).setRelation( savedMeeting, "Location", [geopoint] )

here is a doc https://backendless.com/docs/js/data_set_relation_with_objects.html

and make sure that both geopoint and meeting objects are saved before setup relationship

Regards, Vlad


(Ben Foster) #3

Hi Vlad, thank you for your reply.

After trying this relationship method I am receiving the error of:

backendless.min.js:14 Uncaught (in promise) Error: Invalid value for the third argument. The 
argument is required and must contain string values if it sets whereClause or array if it sets 
childObjects.
at o (backendless.min.js:14)
at e.u (backendless.min.js:14)
at backendless.min.js:14
at new Promise (<anonymous>)
at e.setRelation (backendless.min.js:14)
at savedMeeting (index.js:129)

Any ideas as to why the geopoint is not counting as the third argument?

Thanks,
Ben


(Vladimir Upirov) #4

Hey Ben

sorry, it’s my fault,
geopoint must be wrapped to an array, I’ve fixed my previous comment


(Ben Foster) #5

Thanks for your correction,

After trying this I am stuck with the error of:

backendless.min.js:14 Uncaught (in promise) Error: Unable to create relation. Child object with id 
'null' is not found in the related table.
at new t (backendless.min.js:14)
at c (backendless.min.js:14)

It seems there is an ID missing, where can I solve this?


(Vladimir Upirov) #6

make sure that both geopoint and meeting data objects are saved before setup relationship

could you print console.log({ savedMeeting, geopoint }) beforeBackendless.Data.of( "Meetings" ).setRelation line
to see what properties these objects actually contains


(Ben Foster) #7

Both the geopoint and meeting data object are successfully saved and logged back, however the ‘ownerID’ of the meeting data object is null if that makes any difference.


(Vladimir Upirov) #8

what version of JS-SDK do you use?


(Vladimir Upirov) #9

and could you please provide a code snippet to reproduce the problem


(Ben Foster) #10

Version: 5.2.9

I am obtaining the latitude and longitude (which are successfully stored within the geopoint) using a Geocode searching plugin for Leaflet.js.

Here is most of the geopoint-related code:

// On add meeting popup - Leaflet.js initialisation
$('#plusIcon').on('click', function() {
// Create map before application is created
addMeetingMap = L.map('formMap').locate({setView: true, maxZoom: 16});
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
    attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a>, 
Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
    maxZoom: 18,
    id: 'mapbox.streets',
    accessToken: 'pk.eyJ1IjoiYmVuZjk5OSIsImEiOiJjam9zb2VtZzIwcWRlM3dvOWY4dnpka2NtIn0.kBwwI8OkqhN6fKG_C9wxTQ'
}).addTo(addMeetingMap);


// Add Geocode searching to the map
geocoder = L.Control.geocoder().on('markgeocode', function(e) { // Map searching
    var searchCenter = e.geocode.center;
    L.marker(searchCenter).addTo(addMeetingMap);
    addMeetingMap.setView(searchCenter, addMeetingMap.getZoom());

    searchLat =  searchCenter.lat.valueOf();
    searchLng = searchCenter.lng.valueOf();

    // Create Backendless Geopoint
    appointmentLocation =  new Backendless.GeoPoint();
    appointmentLocation.latitude = searchLat;
    appointmentLocation.longitude = searchLng;
    }).addTo(addMeetingMap);
});


// On add meeting
$('#addMeetingBtn').on('click', addMeeting);

function addMeeting() {
// Name
appointmentName = $('#formName').val();

// Time
var dtp = $('#formTime').val();
appointmentTime = new Date(dtp);

var newMeeting = {};
newMeeting.Appointment = appointmentName;
newMeeting.Time = appointmentTime;

//Save meetings object to Backendless database
if((appointmentName !== "") && (appointmentTime !== "")) {
    Backendless.Data.of("Meetings").save(newMeeting).then(savedMeeting).catch(error);
    }
}


function savedMeeting(savedMeeting) {
// Save geopoint within Backendless
appointmentLocation.metadata = {"Meetings": savedMeeting};
var geopoint = Backendless.Geo.savePoint(appointmentLocation);

// Establish a one-to-one relation between the data object and the geopoint using the 'Location' data column
Backendless.Data.of("Meetings").setRelation(savedMeeting, "Location", [geopoint]);

// Process new added meeting
Backendless.Data.of("Meetings").find().then(processResults).catch(error);
}

Thanks again for the help.


(Ben Foster) #11

Sorry I forgot to include the second error that is appearing with this code:

POST https://api.backendless.com/B8F5EE25-85BF-6C69-FFCD-AC6EA1619C00/4035A309-6CF4-03CB-FF8C-686454FF1400/data/Meetings/71E24138-DBD0-7A06-FF70-6CA00DE8B600/Location 400 (Bad Request)

(Vladimir Upirov) #12

now I see where is the problem
var geopoint = Backendless.Geo.savePoint(appointmentLocation);
actually geopoint is not a saved geo point, it’s promise instance
if you can use async/await in your project just add this

 async function savedMeeting(savedMeeting) {
// Save geopoint within Backendless
appointmentLocation.metadata = {"Meetings": savedMeeting};
var geopoint = await Backendless.Geo.savePoint(appointmentLocation);

otherwise you should put code for setting relations into .then()

function savedMeeting(savedMeeting) {
  return Promise.resolve()
    .then(() => Backendless.Geo.savePoint(Object.assign(appointmentLocation, { "Meetings": savedMeeting })))
    .then(geopoint => Backendless.Data.of("Meetings").setRelation(savedMeeting, "Location", [geopoint]))
    .then(() => Backendless.Data.of("Meetings").find())
    .then(processResults)
    .catch(error);
}

(Ben Foster) #13

Using the async/await approach has got it working!

Thank you for your help with these errors, it’s much appreciated.

Thanks again,
Ben