Order internal data sent to Firestore - android

Hi i am working with firebase. When sending a record I get messy data.
Is there a method to order them to my liking? Since I would like to have it in the order of the form.
I leave a fragment of my code, thank you very much for reading.
firebaseAuth.createUserWithEmailAndPassword(correo, password).addOnCompleteListener(task -> {
if (task.isSuccessful()) {
USERUID = firebaseAuth.getCurrentUser().getUid();
DocumentReference documentReference = firebaseFirestore.collection("Clientes").document(USERUID);
Map<String, Object> user = new HashMap<>();
user.put("Nombre y Apellido", nombre);
user.put("Correo", correo);
user.put("Domicilio", domicilio);
user.put("Localidad", localidad);
user.put("Fecha" , FieldValue.serverTimestamp());
documentReference.set(user).addOnSuccessListener(aVoid -> Log.d(TAG, "Cuenta creada, UID de usuario : " + USERUID))
.addOnFailureListener(e -> Log.d(TAG, "Creación de cuenta fallida: " + e.toString()));
startActivity(new Intent(getApplicationContext(), VerificacionDeDatos.class));
finish();
} else {
Light.make(snackbar, "Error al registrarse: " + task.getException().getLocalizedMessage(), R.drawable.ic_error_outline_black_24dp, android.R.color.transparent, R.color.error, Snackbar.LENGTH_SHORT).show();
}
});

Firestore document fields don't have a determined order. What you see in the screenshot is just how the Firebase console chooses to order them. You'll notice they're in alphabetical order. There's no way to change this, but you can do whatever you want with the order in your own app.

Related

Get Realtime-Update of an Array of DocumentReferences

I'm writing a Game, where the users can join a Lobby to play together. Therefore I update the Lobby and the Users, stored in Firestore. The Lobbys in the Lobby-Collection contain an Id, creator, creationDate and an array of all Members (DocumentReferences to User Objects in a Users Collection). The Users contain an Id, name, mail and an active Lobby. Now, when I update the Entries in the Firestore, in there (Firestore) they seem to be correct.. but when I receive a realtimeUpdate (by adding a SnapshotListener) the array of Members seem to be empty.. but I just inserted the Users to the Array and they ARE saved to Firestore..
Maybe nice to know: I convert the Datasets i get from Firestore to local Java-Objects for better handling with UI things
I also have a local HashMap to more or less cache the Objects so i dont have to always load the from Firestore (I know there is already a cache in the Firestore lib.. but i think i need my own)
At the moment I write the changes directly to Firestore and wait for them to come back via RealtimeUpdate to then update my local Objects. I also tried to update my local Objects and then write them to Firestore.. but then I only append my Users to the Members-Array and the array contains mulitple References of the same user..
/**
* Get a Lobby Object from a DocumentSnapshot from Firestrore
* If the Object already exists it will be loaded from the "CacheMap"
*
* #param documentSnapshot DocumentSnapshot with the data from the Firestore
* #param feedback a method to call when the Lobby was retrieved
*/
public static void getLobbyByDocSnap(DocumentSnapshot documentSnapshot, IFeedback feedback) {
final String METHOD = TAG + " #getLobbyByDocSnap";
String lobby_id = documentSnapshot.getString(FIRESTORE_DOCUMENT_ID);
if (allLoadedLobbys.containsKey(lobby_id)) {
Log.d(METHOD, "found object in map for id: " + lobby_id);
feedback.trigger(allLoadedLobbys.get(lobby_id));
return;
}
Log.d(METHOD, "Could not find in Map.. generate through data");
Lobby lobby = new Lobby();
lobby.setId(lobby_id);
lobby.setPrivateLobby(documentSnapshot.getBoolean(FIRESTORE_DOCUMENT_PRIVATELOBBY));
lobby.setCreationDate(documentSnapshot.getDate(FIRESTORE_DOCUMENT_CREATIONDATE));
allLoadedLobbys.put(lobby.getId(), lobby);
//create all Members of the Lobby as User Objects
final List<User> members = new ArrayList<>();
List<DocumentReference> docmems = (List<DocumentReference>) documentSnapshot.get(FIRESTORE_DOCUMENT_MEMBER);
Log.d(METHOD, "get all members of lobby: " + lobby_id);
for (final DocumentReference docmem : docmems) {
/*docmem.collection(FIRESTORE_DOCUMENT_MEMBER).get()
.addOnSuccessListener(queryDocumentSnapshots -> {
Log.d(METHOD, "Found Members for: "+lobby_id+": "+Arrays.toString(queryDocumentSnapshots.getDocuments().toArray()));
//Convert DocumentReference to User-Object
for (DocumentSnapshot document : queryDocumentSnapshots.getDocuments()) {
Log.d(METHOD, "Get User Object from "+UserManager.class.getCanonicalName());
UserManager.getUserByDocSnap(document, o -> members.add((User) o));
}
});*/
UserManager.getUserByRef(docmem, o -> members.add((User) o));
}
lobby.setMember(members);
Log.d(METHOD, "Start getting the Creator of this Lobby: " + lobby_id);
//create an User-Object for the Creator
UserManager.getUserByRef((DocumentReference) documentSnapshot.get(FIRESTORE_DOCUMENT_CREATOR), o -> {
User creator = (User) o;
lobby.setCreator(creator);
Log.d(METHOD, "Got the Creator, now get the artist for: " + lobby_id);
UserManager.getUserByRef((DocumentReference) documentSnapshot.get(FIRESTORE_DOCUMENT_ARTIST), a -> {
User artist = (User) a;
Log.d(METHOD, "Got the Artist. All Infos collected for: " + lobby_id);
//Create The Lobby-Object
lobby.setArtist(artist);
Log.d(METHOD, "Save the Lobby to the CacheMap: " + lobby.toString());
//add it to the given list and trigger the feedback
feedback.trigger(lobby);
});
});
documentSnapshot.getReference().addSnapshotListener((snapshot, e) -> {
if (e != null) {
Log.w(METHOD+"+new", "Listen failed.", e);
return;
}
if (snapshot != null && snapshot.exists()) {
Log.d(METHOD + "*new", "Current data: " + snapshot.getData());
String update_lobby_id = snapshot.getString(FIRESTORE_DOCUMENT_ID);
Lobby update_lobby = allLoadedLobbys.get(update_lobby_id);
update_lobby.setCreationDate(snapshot.getDate(FIRESTORE_DOCUMENT_CREATIONDATE));
update_lobby.setPrivateLobby(snapshot.getBoolean(FIRESTORE_DOCUMENT_PRIVATELOBBY));
UserManager.getUserByRef(snapshot.getDocumentReference(FIRESTORE_DOCUMENT_ARTIST), o -> update_lobby.setArtist((User) o));
UserManager.getUserByRef(snapshot.getDocumentReference(FIRESTORE_DOCUMENT_CREATOR), o -> update_lobby.setCreator((User) o));
List<User> update_member = update_lobby.getMember();
update_member.clear();
List<DocumentReference> update_docmems = (List<DocumentReference>) documentSnapshot.get(FIRESTORE_DOCUMENT_MEMBER);
//update_lobby.setMember(update_member);
Log.d(METHOD+"*new", "get all updated members of lobby: " + update_lobby_id);
Log.d(METHOD+"*new", "members DocRef List: " + update_docmems);
/*for (final DocumentReference update_docmem : update_docmems) {
Log.d(METHOD+"*new", update_docmem.getId());
UserManager.getUserByRef(update_docmem, o -> {
Log.d(METHOD+"*new",((User) o).toString());
update_lobby.addMember((User) o);
});
}*/
getMemberList(update_docmems, new ArrayList<>(), o -> {
List<User> mems = (List<User>) o;
update_lobby.getMember().clear();
update_lobby.getMember().addAll(mems);
});
} else {
Log.d(METHOD+"*new", "Current data: null");
}
});
}
private static void getMemberList(List<DocumentReference> update_docmems, List<User> member, IFeedback feedback){
final String METHOD = TAG + " #getMemberList";
/*if(null == member){
member = new ArrayList<>();
}*/
if(update_docmems.isEmpty()){
feedback.trigger(member);
return;
}
DocumentReference docref = update_docmems.get(0);
UserManager.getUserByRef(docref, o -> {
member.add((User) o);
Log.d(METHOD, o.toString());
update_docmems.remove(0);
getMemberList(update_docmems, member, feedback);
});
}
The Realtime only provides the "normal" Data but not the array of references. When I initialy load the Data from Firestore i get the actual Data of the Firestore (not empty). But I want to get the whole Document, inluding the "normal" Data (id, creationDate, ...) and the whole array of members.
I already burned 1.5 days to solve this and I cant figure out, whats wrong..
Never mind, i got my error.... really stupid one ^^
in the part where i updated my objects, when the firestore changes.. i used the wrong/old DocumentSnapshot. So I used the inital Members-Array not my new updated one :D
should be:
List<DocumentReference> update_docmems = (List<DocumentReference>) snapshot.get(FIRESTORE_DOCUMENT_MEMBER);
instead of:
List<DocumentReference> update_docmems = (List<DocumentReference>) documentSnapshot.get(FIRESTORE_DOCUMENT_MEMBER);
Now i get my updates correctly :D

Firestore adding hashmaps to a map field in Firestore

I am trying to create a map of objects in my firestore database using key->value pairs.
The idea is to have a map of room objects within my Properties documents where living room would be the key and the object that value. Like the image below
I am getting lost with the correct way to add the objects into firestore as the rooms map is already there so how do I add a key->value pair into it ??
I also need to perform the search I have in the below code so I can grab the Properties document and add the objects into the room map field
FirebaseFirestore db = FirebaseFirestore.getInstance();
final CollectionReference propertyRef = db.collection("Properties");
final Room room = new Room(roomName, feet, inches, imageUrl);
propertyRef.whereEqualTo("propertyId", propertyId).get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot doc : Objects.requireNonNull(task.getResult())) {
propertyRef.document(doc.getId())
-----> .update("rooms", ""+roomName+"", room);
Log.d(TAG, "Firebase Success= " + imageUrl);
Toast.makeText(CreatePropertyActivity3.this, "Property Created", Toast.LENGTH_LONG).show();
exProperties();
}
} else {
Toast.makeText(CreatePropertyActivity3.this, "Error check log", Toast.LENGTH_LONG).show();
}
}
});
Use the document(String) method on the db, which as per docs will create the document if it does not exist (https://firebase.google.com/docs/firestore/manage-data/add-data)
Map<String, Object> room = new HashMap<>();
room.put("feet", "...");
...
db.collection("rooms").document("the new room id")
.set(room)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
...
}
})
.addOnFalureListener(...)
This is if you know the IDs of your documents, or want to set the ID yourself. If so, you can replace the argument passed to .document(...) before adding a new item. Alternatively, you could use the add() method which will create a new document with an auto-generated ID for you.
In your case, it seems as though you are setting your own meaningful ids (e.g. livingroom, kitchen) and you should be changing the propertyId variable before adding a map. However, that is redundant since you already have an attribute (i.e. name) that describes the room. So use add() and avoid querying for a document that would not exist to begin with:
final HashMap<String, Object> newRoom = new HashMap<>();
newRoom.put(roomName, room);
...
propertyRef.add(newRoom)
.addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
#Override
public void onSuccess(DocumentReference documentReference) {
Log.d(TAG, "DocumentSnapshot written with ID: " + documentReference.getId());
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w(TAG, "Error adding document", e);
}
});
In fact, because you were using whereEqualTo you were always fetching a reference to the same document and overwriting its content. Just use the add() functionality and check the docs for more examples. Hope that helps!

I am looking to retrieve email of current user after fetching their userUID from the attendance collection

I know this is normally done by checking who is logged in and using this code.
FirebaseUser user = mAuth.getCurrentUser();
if (user != null){
username.setText("Welcome " +user.getEmail());
}
But in the following code I am retrieving the userUID from my attendance collection on cloud firestore and am looking to use that to get the email associated with that userUID.
Here is my code:
public void viewAttendance(View v) {
attendanceRef2.orderBy("sessionID", Query.Direction.ASCENDING)
.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
String data = "";
for (QueryDocumentSnapshot documentSnapshot : queryDocumentSnapshots) {
Attendance attendance = documentSnapshot.toObject(Attendance.class);
String sessionID = attendance.getSessionID();
String attendanceUID = attendance.getUserUID();
data+= "Session ID: " +sessionID+ "\n" + "Student: " +attendanceUID+ "\n\n";
textViewData.setText(data);
}
}
});
}
So, u r saying, you want to retrieve email addresses from attendenceUID(i.e.,userId).
If yes,
You cannot retrieve the data of all authenticated user from Firebase Authentication, however you can only get the data of current user.
To get data of all users u need to use Admin SDK
Here is an example to it :
UserRecord userRecord = FirebaseAuth.getInstance().getUser(uid);
// See the UserRecord reference doc for the contents of userRecord.
System.out.println("Successfully fetched user data: " + userRecord.getUid());
In your case what u can do is :
UserRecord userRecord = FirebaseAuth.getInstance().getUser(attendanceUID);
String email = userRecord.getEmail();
Or u can use List to store them all.

Reading data from firebase database fails

I am reading the data from the firebase database.Following is snapshot of the data stored in database.
In the snap string starting with "8SS..." is the uid of the user. Following is the code for retrieving the data from firebase database.
//To check if uid of current user and database user matches.
Query q = FirebaseDatabase.getInstance().getReference().child("Location").child(user.getUid()).equalTo(FirebaseAuth.getInstance().getCurrentUser().getUid());
q.addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot singleSnapshot : dataSnapshot.getChildren()){
Log.d(TAG, "Yay!!");
User us = singleSnapshot.getValue(User.class);
String string = "Name: "+ us.getName()+"\nAddress: "+ us.getlat()+ us.getlon()+ "\n\n";
n.setText(string);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
// read query is cancelled.
Log.d(TAG, "loadPost:onCancelled", databaseError.toException());
}
});
User class contains getters and setters.
The error is that only empty Text View appears concluding reading from database fails.
How to evaluate if query is true or false?
What is the error while reading from ValueEventListener()?
I tried using this:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("Location").child("8SS0uk4FmiPUtXP208Tx8Cqxt2z2");
And then calling on ref.addListenerForSingleValueEvent() but still nothing gets displayed.
I tried using this:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("Location").child(user.getUid());
This gives dataSnapShot : "DataSnapshot={key='-Kn...', value="latitude:.., longitude:..., Name:..."}. But this is not how I expected it to be.
The database structure should have been Location --> Uid --> Name : "Jane", .. .
This is my code for inserting data in the database.
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser() ;
refDatabase = FirebaseDatabase.getInstance().getReference().child("Location").child(user.getUid());
DatabaseReference newPost = refDatabase.push();
//the push() command is already creating unique key
Map<String, String> mapname = new HashMap<String, String>();
mapname.put("Name", n.getText().toString());
mapname.put("latitude", Double.toString(lat));
mapname.put("longitude", Double.toString(longt));
mapname.put("user id", user.getUid());
newPost.setValue(mapname);
I solved this question by introducing multiple for loops.
So, the snapshot of my first child was dataSnapShot : "DataSnapshot={key='-Kn...', value="latitude:.., longitude:..., Name:..."}.
Below is the code to extract all the values and keys :
mRef.addValueEventListener(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d(TAG, "Children" + dataSnapshot.getKey());
for(DataSnapshot singleSnapshot : dataSnapshot.getChildren()){
String st = singleSnapshot.getKey();
Log.d(TAG, "Yay!!" + singleSnapshot.child(st));
st = "";
int count=0;
for(DataSnapshot singleSnap : singleSnapshot.getChildren()) {
Log.d(TAG, "String" + singleSnap.getValue());
//n.setText(us.getName());
if(count==0) {
st = "Name: " + singleSnap.getValue() + '\n';
}
else if(count==1) {
st = st + "Latitude: " + singleSnap.getValue() + '\n';
}
else if(count==2) {
st = st + "Longitude: " + singleSnap.getValue() + '\n';
}
count++;
}
final TextView rowTextView = new TextView(Menu5.this.getActivity());
rowTextView.setText((CharSequence) st);
ll.addView(rowTextView);
}
}
This gives single key and value pair for every unique id of created by push.So, I had to hard code the concatenation and display as the structure will remain same throughout the app.
Why are you using equal to and then getting the current user. .child(user.getUid()) should already be your current user which gives you the value of the child you are trying to listen to.
I think the uuid's are the children of "8SSOuk.......".
So it should look something like this:
FirebaseDatabase.getInstance().getReference().child("Location").child("8SSOuk.......").child(user.getUid());

multiples removevalue() from Firebase not working

My code works this way: when I'm on a post and I press "ok" on a AlertDialog.Builder then I go to:
private void borrar_post(){
Intent intent = new Intent(PostDetailActivity.this, MainActivity.class);
intent.putExtra("EXTRA_BORRAR_POST", mPostKey);
startActivity(intent);
}
I come back to main activity and I see if there's anything I need to delete:
String borrar = getIntent().getStringExtra("EXTRA_BORRAR_POST");
if (borrar != null) {
DatabaseReference mipost = FirebaseDatabase.getInstance().getReference();
mipost.child("user-posts").child(getUid()).child(borrar).removeValue();
mipost.child("posts").child(borrar).removeValue();
mipost.child("post-comments").child(borrar).removeValue();
}
I delete my post from the 3 places I have it on my firebase realtime database. The tree is:
It's possible I don't have anything on "post-comments", so I understand I might have a problem there (maybe I should check if there's something there before) but even when I comment that line, I keep having the same problem:
Sometimes everything gets deleted, sometimes nothing, most of the times only "user-posts" child gets deleted.
I know there's similar questions to mine, but I can't seem to find the mistake, any help?
Do you have security rules that limit write access as a function of the current value at a location? That might explain why some removes succeed and others fail.
To understand why some calls to removeValue() are failing, add a CompletionListener. You can define a debug listener as a field in your activity like this:
private DatabaseReference.CompletionListener mRemoveListener =
new DatabaseReference.CompletionListener() {
#Override
public void onComplete(DatabaseError error, DatabaseReference ref) {
if (error == null) {
Log.d(TAG, "Removed: " + ref);
// or you can use:
System.out.println("Removed: " + ref);
} else {
Log.e(TAG, "Remove of " + ref + " failed: " + error.getMessage());
}
}
};
Then add it to each of your calls to removeValue():
String borrar = getIntent().getStringExtra("EXTRA_BORRAR_POST");
if (borrar != null) {
// always good to log important values
Log.d(TAG, "borrar= " + borrar);
DatabaseReference mipost = FirebaseDatabase.getInstance().getReference();
mipost.child("user-posts").child(getUid()).child(borrar).removeValue(mRemoveListener);
mipost.child("posts").child(borrar).removeValue(mRemoveListener);
mipost.child("post-comments").child(borrar).removeValue(mRemoveListener);
}

Categories

Resources