I have my firestore collection structure as shown in the image.
Following is the main collection name which contains currently logged userId as a document ("AuScbj..")
which contains a subcollection called uIds which contains the user ids of users he follows.
When logged in user ("AuScbj..") visits a particular user profile, how can I check whether that profile user's Id available in his following list just by querying like below
firebaseFirestore.collection("Following)
.document(FirebaseAuth.getInstance().getCurrentUser().getUid())
.collection("uIds").where(
You're looking for .where(fieldPath: "uids", opStr: "array-contains", value: followingUID). It should work with your simple "array" data.
To check if id1 is present inside the uIds array in a really simpler manner, first, you should create a class:
class Document {
List<String> uIds;
}
Then get the "AUScbTj5MpNY.." document and read the content of the uIds array using the following method:
private void checkId(String id) {
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference followingRef = rootRef.collection("Following");
DocumentReference uidRef = followingRef.document(uid);
uidRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
List<String> uIds = document.toObject(Document.class).uIds;
if (uIds.contains(id)) {
//Update the UI
}
} else {
Log.d(TAG, "No such document");
}
} else {
Log.d(TAG, "get failed with ", task.getException());
}
}
});
}
Inside the onComplete, we get the array as a List and check if the id with which we are calling the method, exists inside the array. To make it work, kick it off with:
checkId(id1);
Please also note that:
firebaseFirestore.collection("Following)
.document(FirebaseAuth.getInstance().getCurrentUser().getUid())
.collection("uIds").where(/* ... /*);
Will never work, as uIds is an array inside a document and not a collection.
You can also find more info, in the following article:
How to map an array of objects from Cloud Firestore to a List of objects?
Related
How i can get id of empty document (document without field but contains collections)
for Example
public void getUsersLists(OnSuccessListener<List<String>> callback) {
storeCollection().get(getSource()).addOnCompleteListener(task -> {
if (task.isSuccessful()) {
QuerySnapshot result = task.getResult();
List<String> stringList = parseResult(result);
callback.onSuccess(stringList);
} else {
callback.onError(task.getException());
}
}).addOnFailureListener(callback::onError);
}
private List<String> parseResult(QuerySnapshot result) {
List<String> list = new ArrayList<>();
if (result != null) {
for (DocumentSnapshot snapshot : result.getDocuments()) { <<----documetns is zero
String name = snapshot.getId();
list.add(name);
}
}
return list;
}
private CollectionReference storeCollection() {
return firestore()
.collection(COLLECTION_DATA)
.document(AuthManager.getUserId())
.collection(COLLECTION_STORES);
}
COLLECTION_STORES contain empty document that contain other collections.
But i need to get the name/id of document, collection.getDocuments() return empty list, only after i add field via Firebase console the collection.getDocuments() returns the documents.
Is there a way to get the document name/id? or i must attach a field/object to document in this case?
I am understand that attaching object to this document can solve the issue, but it is also complicates the design.
You can't query for a document that doesn't exist. Firestore indexes used for querying work based on documents and fields that actually exist - an index can't work with things that don't exist.
If there are subcollections organized under a document ID that doesn't exist, you need to know the path of those subcollections in order to work with them, including the document ID. There is no way to programmatically discover them if you don't know the document ID where they're organized.
I cant get user recipe Ids to list
I try to query by whereEqualTo and orderBy but on compile firebase suggested me to create indexing, so I did that but it dont give me any results.
for (String mealType : dishTypeList){
userCollectionReference.document(userId).collection("favourites")
.whereEqualTo("mealType", mealType)
.orderBy("dateWhenSetFavourite", Query.Direction.DESCENDING)
.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
List<String> favouriteRecipeIds = new ArrayList<>();
for (QueryDocumentSnapshot document : task.getResult()){
favouriteRecipeIds.add(document.toObject(FavouriteRecipeModel.class).getRecipeId());
Log.d(TAG, "LIST LIST: " + favouriteRecipeIds);
}
myFirebaseCallBack.onSuccessCallback(favouriteRecipeIds);
}
});
}
I want to get recipeId whereEqualTo by mealType and ordered by dateWhenSetToFavourites
This is my database:
Are you sure that dishTypeList contains the same dish types that are used in the database? If yes, your code looks fine to me. If all your objects in the database contain the recipe id than the following code should work:
favouriteRecipeIds.add(document.toObject(FavouriteRecipeModel.class).getRecipeId());
Otherwise, a more simpler way of getting the document id would be:
favouriteRecipeIds.add(document.getId());
Beside that, everytime you are getting as a result a Task object, check to see if it is successful:
if (task.isSuccessful()) {
//Your logic
} else {
Log.d(TAG, task.getException().getMessage());
}
And also use the else part of the statement to check for an error message.
I am trying to get and display my user's information when they are logged in. (i.e: name, email, phone)
I have tried multiple snippets i have found on youtube and on stack overflow but they have failed. Most tutorials use realtime Database, which is not what i am looking for.
I have also tried making a "users" object.
private void getData(){
FirebaseFirestore db = FirebaseFirestore.getInstance();
db.collection("users")
//.document(FirebaseAuth.getInstance().getCurrentUser().getUid())
.whereEqualTo("email:", FirebaseAuth.getInstance().getCurrentUser().getUid())
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot document : task.getResult()) {
//Toast.makeText(getApplicationContext(),document.getId() +"==>" + document.getData(),Toast.LENGTH_LONG).show();
//Toast.makeText(getApplicationContext(),""+ document.get("Email") ,Toast.LENGTH_LONG).show();
nameEdt.setText((CharSequence) document.get("First Name"));
emailEdt.setText((CharSequence) document.get("Email"));
phoneEdt.setText((CharSequence) document.get("Phone"));
}
} else {
Toast.makeText(getApplicationContext(),"No such document",Toast.LENGTH_LONG).show();
}
}
});
}
Database Structure:
I understand that documents in firestore are not associated with users, but i dont know how to set my code up so that it only retrieves data from the user that is signed in* It works fine for newly created accounts, but if i were to log out and sign in with a different user it will not update the "account/user information".
In short, how would I access and display my database information from signed in users?
Additional Notes: I am using Email and Password for authentication
To access your user data stored in Firestore, it shouldn't be as complicated as you thought, there's no queries needed, you just need to fetch the documents corresponding to the user's uid, and fetch the specific fields or do whatever you need with them, like this:
db.collection("users").document(FirebaseAuth.getInstance().getCurrentUser().getUid())
.get().addOnCompleteListener(task -> {
if(task.isSuccessful() && task.getResult() != null){
String firstName = task.getResult().getString("First Name");
String email = task.getResult().getString("Email");
String phone = task.getResult().getString("Phone");
//other stuff
}else{
//deal with error
}
});
Original Answer:
User information is not stored in the Firestore database, they are associated with the Firebase Authentication which you set up for the log in. To retrieve the related user information, you need to use the related FirebaseAuth APIs. Use this to retrieve the current log in user:
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
Then you can get the name and email with something like this:
String name = user.getDisplayName();
String email = user.getEmail();
For more information, refer to the documentation.
If FirebaseAuth doesn't resolve, that probably means you didn't follow the set up guides correctly and forgot to include the dependency in your gradle file:
implementation 'com.google.firebase:firebase-auth:17.0.0'
After a couple days head butting at trying to find a solution, i have found one that is able to retrieve user information from the database. However it is important to note that because my application is not holding a lot of data so this structure works for me.
So i was essentially on the right track, but with some lack of understanding of firebase i missed a few concepts.
private void getData(){
FirebaseFirestore db = FirebaseFirestore.getInstance();
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
final String current = user.getUid();//getting unique user id
db.collection("users")
.whereEqualTo("uId",current)//looks for the corresponding value with the field
// in the database
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot document : task.getResult()) {
nameEdt.setText((CharSequence) document.get("firstName"));
emailEdt.setText((CharSequence) document.get("email"));
phoneEdt.setText((CharSequence) document.get("phone"));
// These values must exactly match the fields you have in your db
}
}
As mentioned before, documents do not associate with users, but you CAN link them together by creating a field in your db called "whatever your want" (i made mine uId). This is because firebase generates a unique id for each user when authenticated. By creating a field that holds that unique id you are able to retrieve the associated information in that collection.
How to create the field:
I created a "user" object that would grab the uid from my edit text. In my code, i passed the uid wherever i was creating/authenticating a new user/account.
FirebaseUser testUser = FirebaseAuth.getInstance().getCurrentUser(); //getting the current logged in users id
String userUid = testUser.getUid();
String uidInput = userUid;
User user = new User(firstNameInput,lastNameInput,uidInput);
db.collection("users").document(userUid)
.set(user)
.addOnSuccessListener(new OnSuccessListener<Void>() {
note: I believe you can also add it to your hash map if you have it done that way.
I'm working on an app that uses a firestore database with the following hierarchy:
parent_collection:
parent_document:
subcollection:
child_document{
string name}
using collectionGroup I've been able to query subcollection for documents with a certain name, but I don't know how to get the parent_document
db.collectionGroup("subcollection").whereEqualTo("name", searchText).get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if(task.isSuccessful()){
//here I want to get the parent id of all results
}
}
});
What is the best way to achieve that?
The QuerySnapshot points to a number of QueryDocumentSnapshot instances.
From a QueryDocumentSnapshot, you can get the collection it's from with:
snapshot.getRef().getParent()
And then the parent DocumentReference is:
snapshot.getRef().getParent().getParent()
So to get a subscollection of the parent document with:
snapshot.getRef().getParent().getParent().collection("name_of_subcollection")
Yes, I agree... that could've been a bit more readable. :)
You can write like this
List<DocumentSnapshot> documentSnapshotList = value.getDocuments();
for (DocumentSnapshot documentSnapshot : documentSnapshotList) {
DocumentReference dr = documentSnapshot.getReference().getParent().getParent();
// or any field documentSnapshot.get(field);
assert dr != null;
));
} //for end
In case you use stream:
docs = db.collection_group(u'collection_name').stream()
for doc in docs:
path = doc.reference.path # will get you the full path
# then you can manage the path as string
sub_path = path.split('/')[1]
You can get documents of a collection like this:
if(task.isSuccessful()) {
List<DocumentSnapshot> documents = task.getResult().getDocuments();
for(DocumentSnapshot documentSnapshot : documents) {
documentSnapshot.getId();
// or any field documentSnapshot.get(field);
}
}
I'm Trying to build a restaurant app using firestore to store the orders and the users.
I tried 2 methods, first one was to write the ArrayList of orders as a Array in firestore database, but coudn't read them afterwards...
I used DocumentSnapshot.toObject(myclassoflist.class) but this only worked with no array list in the document, only with values = ".."
Then I created a collection of documents (each document is an item) which contains the array as simple values
To understand this take a look at my database
Then, to read them i first get all the document ids
db.collection("orders").get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot document : task.getResult()) {
documentsIDs.add(document.getId());
}
Integer allIdsD = task.getResult().size();
if (allIdsD.equals(documentsIDs.size())) {
readDocs();
}
}
}
});
Then for each document id, i created 3 more db.collection(collection).get() in order to get the inside of each document within the subcollection, using again the function DocumentSnapshot.toObject(myclass.class).
The problem here is that it takes ~0.8 secs to get a complete order from the database, which is a lot considering there could be like 100+ orders per day
My project on GITHUB
Examples from: LimatexMM/app/src/main/java/g3org3/limatexmm/orders.java
EDIT:
I also tried to write the orders as follow:
orderListBig docData = new orderListBig(list, currentUser, adList, docId);
(list is ArrayList, currentUser, adList are objects)
db.collection("orderss").document(docId).set(docData)
and then read it with:
db.collection("orderss").get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot document : task.getResult()) {
orderListBig ahah = document.toObject(orderListBig.class);
allOrders.add(ahah); (ArrayList of ordersListBig)
an part of my order document
As per official documentation regarding the use of arrays in Cloud Firestore you need to know that:
Although Cloud Firestore can store arrays, it does not support querying array members or updating single array elements.
If you only want to get the entire orderList array and get the value of, let's say itemMore, you need to get the reference of that particular document and then iterate over a Map like this:
Map<String, Object> map = documentSnapshot.getData();
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getKey().equals("itemMore")) {
Log.d("TAG", entry.getValue().toString());
}
}
But note, even if orderList object is stored in the database as an array, entry.getValue() returns an ArrayList, not an array.
I better approach for your use-case, would be if you consider this alternative database structure, where each item is the key in a map and all values are true:
orderList: {
"itemMore": true,
"itemMoreValue": true,
"itemMoreOtherValue": true
}
Bafta! ;)