I am using Cloud Firestore in my app and have 2 collections Customers and Properties. I have an activity where the user can update the data contained in a customer document name address etc. This code shown below is working fine.
db.collection("Customers").document(customer.getCustomerId())
.update(
"name", c.getName(),
"email", c.getEmail(),
"phoneNo", c.getPhoneNo(),
"address", c.getAddress(),
"creatorId", c.getCreatorId()
)
.addOnCompleteListener(new OnCompleteListener<Void>() {
I have the document reference of the customers saved in the Properties documents so I can reference which customer owns which property. Using this reference I want to search for Properties containing that reference and update the name field if it has been changed. I have tried adding the code into my method after the onComplete checks for the above code, but it doesn't update the name field every time only every few attempts.
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference propRef = rootRef.collection("Properties");
propRef.whereEqualTo("customerId", customerId).get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : Objects.requireNonNull(task.getResult())) {
Map<Object, String> map = new HashMap<>();
map.put("customer", customerName);
propRef.document(document.getId()).set(map, SetOptions.merge()).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Is there a way to achieve what I am trying to do?
I did think I could do it using batch but from what I have read this does not allow searching.
#AlexMamo
This is a document from my Customers collection
This is a linked document from my Properties collection
Customers Structure
Properties Structure
According to your comments, to solve your the issue, please use the following lines of code:
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference propertiesRef = rootRef.collection("Properties");
CollectionReference customersRef = rootRef.collection("Customers");
customersRef.whereEqualTo("customerId", customerId).get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
String customerName = document.getString("name");
propertiesRef.whereEqualTo("customerId", customerId).get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot doc : task.getResult()) {
propertiesRef.document(doc.getId()).update("customer", customerName);
}
}
}
});
}
}
}
});
See you should use different CollectionReference objects, propertiesRef and customersRef, you are using a single one.
you need to implement the Interface from firestore OnDataChange and receive the new values of your variables bind to your views.
in that case when you modify or update a value in your firestore the change triggers this interface and you can assign the new change.
ValueEventListener myListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Post object and use the values to update the UI
Customer customer = dataSnapshot.getValue(Customer.class);
// ...
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
// ...
}
};
rootRef.addValueEventListener(myListener);
hopefully it works for you.
https://firebase.google.com/docs/database/android/read-and-write?authuser=0
Related
I am using Firestore & Java.
I am trying to change multiple values by query and batch.
My DB
Kullanıcılar
-deneme#deneme.com
--Hayvanlar
---RandomId1
"ozel", "E65" //I WANNA UPDATE THIS (First))
---RandomId2
----Dogru
-----RandomId
------Acep
"ozel", "E65" //AND THIS (Second)
My Code
CollectionReference cr = fs.collection("Kullanıcılar/" + deneme#deneme.com + "/Hayvanlar");
Query query = cr.whereEqualTo("ozel", "E65");
query.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
WriteBatch batch = fs.batch();
for (DocumentSnapshot ds : task.getResult()) {
batch.update(ds.getReference(), "ozel", "E75");
}
batch.commit();
}
}
});
When i run this codes my only first value updates.
I never reach to second value :/
Move batch.commit() outside your for loop
I have a problem when I am fetching my Data from Firebase Firestore. I want to get multiple Documents out of my "Posts" collection and that works fine. But to get my user documents out of my "Users" collection i need to start multiple tasks(Task) that ALL need to be completed before I want to call my callback function and i cant figure out how. Is there even a way to do it with a callback? Ive tried to solve it with Continuations but had a hard time.
Thanks in advance.
Here some simple code i wrote so u can maybe understand the problem a little bit better.
public void getPosts(final postCallback callback) {
final FirebaseFirestore db = FirebaseFirestore.getInstance();
CollectionReference postsRef = db.collection("Posts");
Query postsQuery = postsRef.orderBy("createTime", Query.Direction.DESCENDING).limit(20);
// Starting the post documents
Task<QuerySnapshot> task = postsQuery.get();
task.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if(task.isSuccessful()){
QuerySnapshot querySnapshot = task.getResult();
List<DocumentSnapshot> docsList = querySnapshot.getDocuments();
for(DocumentSnapshot docSnap : docsList){
String userID = docSnap.getString("originalPoster");
// getting user documents
Task<DocumentSnapshot> userTask = db.collection("Users").document(userID).get();
userTask.addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
DocumentSnapshot userDoc = task.getResult();
String userID = userDoc.getId();
String firstName = userDoc.getString("first_name");
String surname = userDoc.getString("surname");
User userObject = new User(firstName, userID, surname);
// cant call my callback right here otherwise its called for every
// completed user fetch
}
});
// cant call my callback right here since its too early
}
}else if(task.isCanceled()){
System.out.println("Fetch failed!");
}
}
});
}
I have the following situation, namely:
I get documents from a database and convert them to objects:
Code:
private void getProductsFromDatabaseBreakfast() {
breakfastProducts.clear();
firebaseFirestore.collection("Users").document(currentUserUID)
.collection("Types of Meals").document("Breakfast")
.collection("Date of Breakfast").document(date)
.collection("List of Products")
.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if(task.isSuccessful()) {
for(DocumentSnapshot documentSnapshot: task.getResult().getDocuments()) {
Log.i("id", documentSnapshot.getId());
breakfastProducts.add(documentSnapshot.toObject(Product.class));
}
}
if(getFragmentRefreshAdapter() != null) {
getFragmentRefreshAdapter().onRefresh();
}
}
});
}
Structure:
Then I display products in RecyclerView:
Going to the merits, I would like the user to be able to change the specifics of the product, and precisely its weight, which will automatically change the other values (calories, protein etc.).
Therefore, after clicking on a given item RecyclerView I go to an activity in which the user can make changes to the product. How can I associate a given product that the user has chosen with the corresponding product in CloudFirestore? That changes would also take place in the document.
I was thinking about incrementing the product ID then I could associate the product with the product position in ReyclerView but I read that it is not good practice or is there any other way?
If the user clicks on an item, then send the name to the other activity and then do a query:
CollectionReference ref = firebaseFirestore.collection("Users").document(currentUserUID)
.collection("Types of Meals").document("Breakfast")
.collection("Date of Breakfast").document(date)
.collection("List of Products");
ref.whereEqualTo("name", name).get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if(task.isSuccessful()) {
for(DocumentSnapshot documentSnapshot: task.getResult().getDocuments()) {
Map<String, Object> data = new HashMap<>();
data.put("weight", 200);
ref.document(documentSnapshot.getId()).set(data, SetOptions.merge());
}
}
}
});
Use the query whereEqualTo to query that will return all names with the name Chicken breast meat, then after task is successful update the document with the data that the user entered.
https://firebase.google.com/docs/firestore/query-data/queries
https://firebase.google.com/docs/firestore/manage-data/add-data#set_a_document
I have my Firestore database in the following way:
Image Database Firestore
I been try this to get the value of sub-collection:
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
DocumentReference bulletinRef = rootRef.collection("facultades").document("3QE27w19sttNvx1sGoqR").collection("escuelas").document("0");
bulletinRef.get()
.addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
Log.d(LOG_TAG, "RESULTADO DE LA CONSULTA" + "===" + document.getData());
}
}
});
But this does return null:
Image result
Please help me.
You are getting null because escuelas is not a subcollection, it is an array that holds objects of type HashMap. So the following line of code:
DocumentReference bulletinRef = rootRef.collection("facultades").document("3QE27w19sttNvx1sGoqR")
.collection("escuelas").document("0");
Will never work. If you want to get the data within the escuelas array, please note that array type fields arrive from the Cloud Firestore database as a List of maps. So please use the following lines of code:
rootRef.collection("facultades").document("3QE27w19sttNvx1sGoqR").get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
List<Object> list = (List<Object>) document.get("escuelas");
//Iterate throught the list and get the data
}
}
}
});
Please also note that while iterating, each element that you get from the list is of type HashMap. So you'll need to iterate again to get the corresponding data within each HashMap object.
Thanks, this really helped me, I used this code to iterate
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
rootRef.collection("facultades").document("3QE27w19sttNvx1sGoqR")
.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
List<Object> list = (List<Object>) document.get("escuelas");
//Iterate throught the list and get the data
Map<String, String> map = new HashMap<>();
map.put("key2", list.toString());
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
}
}
}
});
this is the result: Image result
But i feel confused, how ca I get just this:
image database
Facultades> all documents> escuelas > name
I'm making a simple app in which I want to introduce most liked posts. I'm using Cloud Firestore. My question is how the query should look like in this case? (I'm using Java)
Here's the Firestore tree:
-ROOT
--Posts
---Post
----Likes
Likes collection is set of users' ids.
Assuming that the Likes property is of type number and not String, please use the following code:
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
DocumentReference ref = rootRef.collection("Posts").document("Post");
ref.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
long numberOfLikes = document.getLong("Likes");
Log.d(TAG, String.valueOf(numberOfLikes));
} else {
Log.d(TAG, "No such document");
}
} else {
Log.d(TAG, "get failed with ", task.getException());
}
}
});
The output in your logcat will be the number of likes.