How to add child node under the existing Firebase json structure? - android

I am working on Android project, in which I saved details (email, password, name, mob, usertype, userid) while sign up, now I have to add extra details like long, lat and address to the existing structure for every user. Below is the image for my Firebase stucture, where with the help of brown line I have mentioned exact place I want to add the details.

To update/set specific fileds for an object you can follow the dedicated documentation section
Your code should like like this
private void setUserData(String userId, double lat, double lng) {
Map<String, Object> userUpdates = new HashMap<>();
userUpdates.put("/users/" + userId + "/name_you_want/address", "Groove Street 2");
userUpdates.put("/users/" + userId + "/name_you_want/lat", lat);
userUpdates.put("/users/" + userId + "/name_you_want/lng", lng);
mDatabase.updateChildren(userUpdates, /*Add a complete listener if wanted*/);
}
EDIT: to avoid the extra id, you just need to specify the node name, just by replacing "name_you_want"

Related

Get the value of a map field in cloud firestore

I have a code in getting the value of a map named Address.
Map<String, Object> map = document.getData();
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getKey().equals("Address")) {
Log.i(TAG, entry.getValue().toString());
}
}
And here is the output
{Street=VP Inting Avenue, HouseNo=0186, Town=Tagbilaran City, Barangay=Poblacion I}
But I want to get the values (0186 VP Inting Avenue Poblacion I Tagbilaran City) only and not including their keys.
I think you're looking for:
Log.i(TAG, document.get("Address.HouseNo") + document.get("Address.Street") +
document.get("Address.Barangay") + document.get("Address.Town"));
If you know the exact path of the field, there is no need to loop over all fields. And with the . you can address nested fields.

Google map API return incorrect result for searches

I am new to coding in android and I am trying to use the google map API to display places nearby.
My code is:
public void onClick(View v) {
mMap.clear();
String search = "cvs"
String url = getUrl(latitude, longitude, search);
Object[] dataTransfer = new Object[2];
dataTransfer[0] = mMap;
dataTransfer[1] = url;
GetNearbyData getNearbyData = new GetNearbyData();
getNearbyData.execute(dataTransfer);
}
private String getUrl(double latitude, double longitude, String
nearbyPlace) {
StringBuilder googlePlacesUrl = new
StringBuilder("https://maps.googleapis.com/maps/api/place/nearbysearch/json?");
googlePlacesUrl.append("location=" + latitude + "," + longitude);
googlePlacesUrl.append("&radius=" + PROXIMITY_RADIUS);
googlePlacesUrl.append("&type=" + nearbyPlace);
googlePlacesUrl.append("&sensor=true");
googlePlacesUrl.append("&key=" + "{MY_KEY}");
return (googlePlacesUrl.toString());
}
the URL output is:
https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=40.7692494,-73.9842065&radius=10000&type=cvs&sensor=true&key={MY_KEY}
The problem starts when I change the search word, when I put (under the URL type) cvs/parks/starbucks... (and probably other places) I keep getting the same result. For example: if my location is central park NY, I keep getting results for
Chrysler Building
Hotel Pennsylvania
Hudson New York and more.
Those palaces are not related to my search word (cvs/parks/starbucks...)
Important note is that for banks I do get banks' results.
Can anyone explain me how to solve this problem? why for some words I do get correct results and for other I do not?
Thanks
Please note that none of cvs, parks or starbucks belong to the list of supported types that you can use in nearby search. You can consult the list of supported types in the official Places API documentation:
https://developers.google.com/places/supported_types
I believe you have to use a keyword parameter when you construct the URL instead of the type parameter.
keyword — A term to be matched against all content that Google has indexed for this place, including but not limited to name, type, and address, as well as customer reviews and other third-party content.
source: https://developers.google.com/places/web-service/search#PlaceSearchRequests
For example if I search 'cvs'
https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=40.7692494%2C-73.9842065&radius=10000&keyword=cvs&key=MY_API_KEY
I can see places that are relevant for this search as shown in my screenshot
Search for 'parks'
https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=40.7692494%2C-73.9842065&radius=10000&keyword=parks&key=MY_API_KEY
gives me the following results
Finally search for 'starbucks'
https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=40.7692494%2C-73.9842065&radius=10000&keyword=starbucks&key=MY_API_KEY
returns Starbucks places
I hope this helps!

How to manage firebase database keys?

When using firebase (or any database that aggregates data basing on ids) I nearly always have to keep track of a key of a given value. For example let's assume I have Location class with latitude and longitude fields. When I download if from firebase, besides its two fields, I also want to keep track of the key (node value generated with push() e.g. -K_esEYXNfMBNmgF3fO4) it was downloaded from so I may later update it, delete it etc. I see only two solutions:
Duplicate the data and add key value as another Location class field. That doesn't work nicely because I have to set the key value only after I executed push().
Create generic wrapper class that will keep key and object:
public class Key<T> {
private final String key;
private final T value;
public Key(String key, T value) {
this.value = value;
this.key = key;
}
public String key() {
return key;
}
public T value() {
return value;
}
}
I am using the second approach but it doesn't look really nice. I have this Key class basically throughout all my codebase and when using RxJava plenty of methods have a return type like this: Observable<Key<Location>> and that just looks ridiculous.
What you call ridiculous actually looks quite normal to me.
Alternatively you can include the key in the POJO and annotate it with #Exclude to exclude it from the serialization.
Follow up on #FrankvanPuffelen great answer, do what you want with the below pushkey
Read and Write Data on Android
private void writeNewPost(String userId, String username, String title, String body) {
// Create new post at /user-posts/$userid/$postid and at
// /posts/$postid simultaneously
String key = mDatabase.child("posts").push().getKey();
Post post = new Post(userId, username, title, body);
Map<String, Object> postValues = post.toMap();
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("/posts/" + key, postValues);
childUpdates.put("/user-posts/" + userId + "/" + key, postValues);
mDatabase.updateChildren(childUpdates);
}

How to save GeoFire coordinates along with other items in Firebase database?

I'm developing an app and saving some strings like postedAtTime, postedBy, postedOnDate in Firebase database. I want to save the GeoFire coordinates in the same node in which all the above string are saved, so that later I can do query, easily.
Here's the path to which I'm saving all the strings:
databaseReferenceHRequests = firebaseDatabase.getReferenceFromUrl("https://appName-e1a35.firebaseio.com/requests/");
This is how I'm saving it:
// in onButtonClicked method:
postNewRequest(null, imageUID, MainActivity.userName.getText().toString(), time, date, utcFormatDateTime, MainActivity.userEmail.getText().toString(), geoFire);
// the method:
public void postNewRequest(Bitmap bitmap, String imageUIDh, String postedBy, String postedAtTime, String postedOnDate, String utcFormatDateTime, String userEmail, GeoFire geoFire) {
HRequest hRequest = new HelpRequest(null, imageUIDh, postedBy, postedAtTime, postedOnDate, utcFormatDateTime, userEmail, geoFire);
databaseReferenceHRequests.push().setValue(hRequest);
}
Here's how it is getting saved in the database:
What I want is to save the GeoFire coordinates in the same node, which is -KLIoLUsI0SpQZGpV1h4 here. This is just a push ID and it gets generated randomly.
I tried it by giving this reference:
geoFire = new GeoFire(firebaseDatabase.getReferenceFromUrl("https://appName-e1a35.firebaseio.com/requests/"));
And then pushing it with other items as shown above. But, this saved only GeoFire coordinates and not the other items under the node requests.
So, what should be my GeoFire reference so that it gets saved along with all the data in the same node?
What is going wrong here? Please let me know.
Frank's answer is correct, but I want to give an example.
Your database structure should be like this.
{
"items" : {
<itemId> : {
"someData" : "someData",
...
}
},
"items_location" : {
<itemId> : {
<geofireData> ...
}
}
}
To get the data, first you need to do GeoQuery at items_location node and then get the data on the onKeyEntered method. The parameter key is itemId from my example.
geoFire = new GeoFire(FirebaseDatabase.getInstance().getReference().child("items_location");
geoQuery = geoFire.queryAtLocation(geoLocation), radius);
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
#Override
public void onKeyEntered(String key, GeoLocation location) {
//retrieve data
}
};
Hope this helps.
EDIT
How to push the item and set the geofire data.
String itemId = ref.child("items").push().getKey();
ref.child("items").child(itemId).setValue(item);
geoFire = new GeoFire(ref.child("items_location"));
geoFire.setLocation(itemId, new GeoLocation(lattitude, longitude));
EDIT Save the item data and geofire data in one API call
GeoHash geoHash = new GeoHash(new GeoLocation(latitude, longitude));
Map<String, Object> updates = new HashMap<>();
updates.put("items/" + itemId, item);
updates.put("items_location/" + itemId + "/g", geoHash.getGeoHashString());
updates.put("items_location/" + itemId + "/l", Arrays.asList(latitude, longitude));
ref.updateChildren(updates);
When you use Geofire, you have two lists of data:
a list of items with their regular properties
a list of geohash indexes and their associated keys, which you query through Geofire
You use the keys to get from the Geoquery results to the regular items. That's why the events for Geofire are called "Key Entered", "Key Exited", etc.
Trying to store them in one node is a bad idea, since you're mixing mostly static data (the properties of your items) with highly volatile data (the geo-location information). Separating the two out leads to better performance, which is why Geofire enforces it.
While there may be use-cases where the properties and geo-data are equally dynamic/static, GeoFire does not support keeping the geo-data and other properties in a single location.
You can use Firebase functions to enter it for you on every new entry
let functions = require('firebase-functions');
let GeoFire = require('geofire');
exports.testLocation = functions.database.ref('/items/{item}').onWrite(event => {
let data = event.data.val();
console.log(data);
console.log(event.params.item);
if (data.location && data.location.coords) {
console.log('Update GeoFire');
let ref = event.data.adminRef.parent.parent.child('/items_locations'));
let key = event.params.test;
let location = [data.location.coords.latitude, data.location.coords.longitude]);
let geoFire = new GeoFire(ref);
geoFire.set(key, location).then(() => {
console.log('Update succesfull');
}).catch(error => {
console.log(error);
});
}
}
For those more recently coming to this post with the same question, this is possible with the Geofirestore library, which supports Geofire for apps built on top of the Firebase Firestore database.

How do you include a username when storing email and password using Firebase (BaaS) in an Android app?

The Firebase createUser() method takes an email and password field, but what if I want to also allow the user a custom username similar to Snapchat, Instagram, StackOverflow etc? Is there any way to modify the existing method to accept that field as well or do I need to do push and manage this info manually and if so how?
This is my first attempt at storing the desired user info:
Firebase ref = new Firebase(firebaseURL);
ref.createUser(email, password, new Firebase.ValueResultHandler<Map<String, Object>>() {
#Override
public void onSuccess(Map<String, Object> result) {
System.out.println("Successfully created user account with uid: " + result.get("uid"));
//Sign user in
Firebase ref = new Firebase(firebaseURL);
ref.authWithPassword(email, password, new Firebase.AuthResultHandler() {
#Override
public void onAuthenticated(AuthData authData) {
System.out.println("User ID: " + authData.getUid() + ", Provider: " + authData.getProvider());
//Save user info
Firebase userRef = new Firebase(firebaseURL + "Users/");
User user = new User(username, authData.getUid());
userRef.setValue(user);
Is this good practice? I figured storing the UID with the username may help me in the future handling changes etc. Also, should I be implementing the updateChildren() or push() method so the entries do not get overwritten if this is a social media app?
This is my second attempt:
#Override
public void onAuthenticated(AuthData authData) {
System.out.println("User ID: " + authData.getUid() + ", Provider: " + authData.getProvider());
//Save user info and username
Firebase ref = new Firebase(firebaseURL);
Map<String, String> map = new HashMap<String, String>();
map.put("email", email);
map.put("username", username);
map.put("provider", authData.getProvider());
ref.child("users").child(authData.getUid()).setValue(map);
Yes, there is a way how to update user info in Firebase.
All you need - to read this article in Firebase docs and implement method described here Update user info
Using this method you can update diplayName property of FirabaseUser object. Just set user name for displayName property and commit your changes.
I hope this will help you.
Show a form with three fields:
Username
Email address
Password
Send the latter two to Firebase's createUser() method. Then in the completion callback for that, store all information in your Firebase database.
var userName, emailAddress, password;
// TODO: read these values from a form where the user entered them
var ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.createUser({
email : emailAddress,
password : password
}, function(error, authData) {
if (error) {
console.log("Error creating user:", error);
} else {
// save the user's profile into the database so we can list users,
// use them in Security and Firebase Rules, and show profiles
ref.child("users").child(authData.uid).set({
provider: authData.provider,
name: userName
});
}
});
See this page on storing user data in the Firebase docs for more information.
Here is one way to store the registered details in database,
Map<String, String> parameters = new HashMap<>();
FirebaseDatabase mFirebaseInstance;
parameters.put(Constant.TAG_USER, strUsrS.trim());
parameters.put(Constant.TAG_EMAIL, strEmailS.trim());
parameters.put(Constant.TAG_PASS, strPassS.trim());
//use this if needed(pushId)
String pushId = mFirebaseInstance.getReference(YOUR TABLE NAME).getRef().push().getKey();
parameters.put(Constant.TAG_KEY, pushId.trim());
mFirebaseInstance.getReference(YOUR TABLE NAME).getRef().child(strUsrS.trim()).setValue(parameters);
Try this implementation and execute... Thankyou
Hope that you aware about how to alter(create) table with required fields in firebase.
Related question & discussion with solutions

Categories

Resources