Multi-paths update and Geofire
See original GitHub issueHi,
As mentioned here, I think it should be great to easily multi update data paths and a geofire path at the same time. As the set of Geofire is pretty complex, it’s hard to directly copy/paste the code to make it works.
Here the use case : (I use the same as the link above but add a path to know where a post is located). So the structure :
{
posts: {
post1: {
from : user1,
message: "Hi",
},
post2: {
from : user2,
message: "Hey",
}
},
posts-location: {
post1: {
g : 'xxxxxxxx',
l: {
0 : latitude,
1 : longitude
}
},
post2: {
g : 'xxxxxxxx',
l: {
0 : latitude,
1 : longitude
}
}
},
users: {
user1: {
posts: {
post1: true
}
},
user2: {
posts: {
post2: true
}
}
}
}
Now I can add a post at the same time at users and posts (with multi-path update). But I need to set the position after. In my use case, a post without a position is not valid data, it’s for that the best should be to do the 3 updates at the same times (if one fails, all fail).
Deleting Geofire path is easy (using update(null)), we can multi-update for delete, but for set/update, I loop for a way to do that easily,
Cheers, Clément
Issue Analytics
- State:
- Created 8 years ago
- Reactions:1
- Comments:8
Top GitHub Comments
+1. Atomic updates are really important to ensure the integrity of the database.
checking the set function inside module at …/node_modules/geofire/dist/geofire/index.cjs.js" there wasn’t really sophisticated method or external library that help update geofire hash to firebase. It’s just plan method and validation.
as @ghost suggested earlier, instead of returning a promise for updating the data, you can simple return newData, then do the uploading yourself.
you can simply copy and paste below function, then you can do something like
`var map = {}; map[‘eventIndex/’ + v] = getGeoFireHashes(eventKey, [location.lat, location.lon]);
firebase.database().ref(‘/’).update(map);`
`function getGeoFireHashes(keyOrLocations, location) { var locations; if (typeof keyOrLocations === ‘string’ && keyOrLocations.length !== 0) { // If this is a set for a single location, convert it into a object locations = {}; locations[keyOrLocations] = location; } else if (typeof keyOrLocations === ‘object’) { if (typeof location !== ‘undefined’) { throw new Error(‘The location argument should not be used if you pass an object to set().’); } locations = keyOrLocations; } else { throw new Error(‘keyOrLocations must be a string or a mapping of key - location pairs.’); } var newData = {}; Object.keys(locations).forEach(function (key) { validateKey(key); var location = locations[key]; if (location === null) { // Setting location to null is valid since it will remove the key newData[key] = null; } else { validateLocation(location); var geohash = geohashForLocation(location); newData[key] = encodeGeoFireObject(location, geohash); } }); return newData; }
/**
/**
/**
function validateKey(key) { var error; if (typeof key !== ‘string’) { error = ‘key must be a string’; } else if (key.length === 0) { error = ‘key cannot be the empty string’; } else if (1 + GEOHASH_PRECISION + key.length > 755) { // Firebase can only stored child paths up to 768 characters // The child path for this key is at the least: ‘i/<geohash>key’ error = ‘key is too long to be stored in Firebase’; } else if (/[[].#$/\u0000-\u001F\u007F]/.test(key)) { // Firebase does not allow node keys to contain the following characters error = ‘key cannot contain any of the following characters: . # $ ] [ /’; } if (typeof error !== ‘undefined’) { throw new Error(‘Invalid GeoFire key '’ + key + '': ’ + error); } }
function validateLocation(location) { var error; if (!Array.isArray(location)) { error = ‘location must be an array’; } else if (location.length !== 2) { error = 'expected array of length 2, got length ’ + location.length; } else { var latitude = location[0]; var longitude = location[1]; if (typeof latitude !== ‘number’ || isNaN(latitude)) { error = ‘latitude must be a number’; } else if (latitude < -90 || latitude > 90) { error = ‘latitude must be within the range [-90, 90]’; } else if (typeof longitude !== ‘number’ || isNaN(longitude)) { error = ‘longitude must be a number’; } else if (longitude < -180 || longitude > 180) { error = ‘longitude must be within the range [-180, 180]’; } } if (typeof error !== ‘undefined’) { throw new Error(‘Invalid GeoFire location '’ + location + '': ’ + error); } }`