Getting Invalid collection reference error when accessing Firestore - java

I am unable to from a new collection in Firestore using the below code. It always gives me the error:
Invalid collection reference. Collection references must have an odd number of segments, but Stores/Stored_Product_Storage has 2.
ProductClass dummyProduct = new ProductClass("dummyitem", 0, "none", 0);
db.collection("Stores").document("Stored_Product_Storage").collection(String.valueOf(docLocation)).add(dummyProduct);
db.collection("Stores").document("Stored_Product_Storage").collection(String.valueOf(docLocation))
.whereGreaterThan("price", 0)
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
products.clear();
for (QueryDocumentSnapshot document : task.getResult()) {
Log.d(TAG, document.getId() + " => " + document.getData());
String name = document.get("name").toString();
int price = Integer.parseInt(document.get("price").toString());
float units = Float.parseFloat(document.get("units").toString());
String unitType = document.get("unitType").toString();
ProductClass product = new ProductClass( name, price, unitType, units);
products.add(product);
}
progressDialog.dismiss();
storeProductUpdateActivityAdapter.notifyDataSetChanged();
} else {
Log.w(TAG, "Error getting documents.", task.getException());
}
}
});
When I directly insert a string instead of String.valueOf(docLocation) then a new collection along with a document is created for inserting the dummy product data. But if I try to use a variable instead of directly giving the string in that field then it gives me the collection reference error. The same happens while reading the data. I am storing a custom string id in docLocation.Can anyone help me in fixing this? Thanks in advance.

It's almost certainly the case that String.valueOf(docLocation) is returning an empty string. You'll need to check that before passing it to document().

Related

How to retrieve a value from a sub-field of a map field in a document in Firestore DB?

I am planning to use the value of a sub-field of a map field in my document for other purposes but it seems that I cannot retrieve it. I have found an answer here on this website but the solution code to get the value is too much for me. I can use the solution code to get the value but if there is the simplest way to get it, kindly drop the answer here.
This is the screenshot of Firestore DB where I need to get is the Boolean value of deleted inside a map field with the UID as field name:
To get the value of the "deleted" fields that exists inside that Map object, please use the following lines of code:
FirebaseFirestore db = FirebaseFirestore.getInstance();
CollectionReference candidatesRef = db.collection("Candidates");
DocumentReference emailRef = candidatesRef.document("ravalera...#umak.edu.ph");
// ^ add entire address ^
emailRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
Map<String, Boolean> map = (Map<String, Boolean>) document.get("PADc...ayU2");
// ^ add entire ID
boolean deleted = map.get("deleted");
Log.d(TAG, "deleted: " + deleted);
} else {
Log.d(TAG, "No such document");
}
} else {
Log.d(TAG, "get failed with ", task.getException());
}
}
});
The result in the logcat will be:
deleted: true

Retrieving firebase data in one go

I am trying to retrive a collection named jobs in which each job contains 3 different fields. I then want to display each job with all 3 field on an array list. My app runs but it returns one item which says: java.lang.field#2234456
This is my code:
ListView jobList;
ArrayList<String> jobInfo = new ArrayList<String>();
ArrayAdapter arrayAdapter;
Task hello;
String hi;
FieldPath ha;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_see_jobs2);
jobList = (ListView) findViewById(R.id.jobList);
setTitle("Hello");
arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, jobInfo);
jobList.setAdapter(arrayAdapter);
jobList.setAdapter(arrayAdapter);
hello = FirebaseFirestore.getInstance().collectionGroup("jobs").get().addOnCompleteListener(new
OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
hi = QuerySnapshot.class.getFields().toString();
hi.toString();
}
});
jobInfo.add(QuerySnapshot.class.getDeclaredFields().toString());
}
This is not the way to get data from a Firestore document:
QuerySnapshot.class.getFields()
Instead this looks up the fields that are declared on the QuerySnapshot class, which is not at all what you're interested in.
If we check the Firebase documentation on getting data from multiple documents, you'll see that we can get the data with:
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
Log.d(TAG, document.getId() + " => " + document.getData());
}
} else {
Log.d(TAG, "Error getting documents: ", task.getException());
}
}
So this:
Loops over the documents that you get back from the database.
Then gets the data from each document with document.getData(), which returns a Map.
If you look at the reference documentation for the DocumentSnapshot class, you'll see that we can also get the value for a specific field with:
document.get("nameOfThefield")
You'll then want to add the field values to jobInfo.add(...) inside the onComplete method.

TextView not able to setText with data from Firestore

I'm fetching data from Firestore. I want to set the string data to a TextView. I'm able to get the data successfully . i.e I'm able to log it in the logcat. But when I try to set the text,it shows null in place of the data
Here is my code :
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
yourSector=view.findViewById(R.id.Sector_tv);
yourPincode=view.findViewById(R.id.Pincode_tv);
DocumentReference docRef = db.collection("customerUsers").document(userID);
docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
pincode = document.getString("pincode");
sector = document.getString("sector");
Log.d("pincodetest", "onComplete: "+pincode);
} else {
Log.d("docref", "No such document");
}
} else {
Log.d("docref", "get failed with ", task.getException());
}
}
});
String sectorText="Sector : " + sector;
String pincodeText="Pincode : "+pincode;
yourSector.setText(sectorText);
yourPincode.setText(pincodeText);
My logcat (shows the correct data):
2020-06-14 00:41:43.779 14633-14633/? D/pincodetest: onComplete: 110001
When I set the text, on my screen I get:
Sector : null
PS: Strings pincode,sector have already been declared outside onViewCreated
The OnCompleteListener completes asynchronously so you need to place your setTexts within the onComplete method of it. In other words, the sector and pincode local variables are not populated with data when they are accessed for the concatenation to form the sectorText and pincodeText Strings.
In simpler terms, the onComplete method runs after the string concatenation. Therefore, during the string concatenation the value of the variables sector and pincode are still null.
I've done a little fix in the code below:
if (document.exists()) {
pincode = document.getString("pincode");
sector = document.getString("sector");
Log.d("pincodetest", "onComplete: "+pincode);
String sectorText="Sector : " + sector;
String pincodeText="Pincode : "+pincode;
yourSector.setText(sectorText);
yourPincode.setText(pincodeText);
}

How do i List out Firebase Document wihtin a Collection?

I have a collection called 'Quiz' and its document contains Quiz category. How do I get all the category documents? Like only(Science,Technology..etc..)
View Image
I have tried with this code:
db.collection("Quiz")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
Log.d("KKKK : ", document.getId() + " => " + document.getData());
}
} else {
Log.d("KKKK : ", "Error getting documents: ", task.getException());
}
}
});
But it never returns a value I have changed Firebase rule to allow read, write: if true;
If db object is defined as follows:
FirebaseFirestore db = FirebaseFirestore.getInstance();
To get all documents that exist within Questions subcollection, please use the following reference:
db.collection("Quiz").document("Science")
.collection("Questions")
.get()
.addOnCompleteListener(/* ... */);
See, you need to add all collection and document names in your reference, not only one, as it is in your actual code right now.

Firestore not querying second collection

I'm kind of new to android studio and firestore database and
I'm having some trouble with querying my second firestore collection. As the title says, i am querying two collections, first one is:
with the code :
firestore = FirebaseFirestore.getInstance();
FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder()
.build();
firestore.setFirestoreSettings(settings);
firestore.collection("Obiective").get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
//<--------- Check if firestore entry is already downloaded into file --------->
SingletonObjectivesId.getInstance().getIds().clear();
for (QueryDocumentSnapshot document : task.getResult()) {
Log.d(TAG, task.getResult().size() + " number of documents");
SingletonObjectivesId.getInstance().setSize(task.getResult().size());
if(document.exists() && document != null) { ...
and the second collection have the following format:
with the code:
firestore.collection("Routes")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
Log.d(TAG, task.getResult().size() + " = task.getResult().size()");
for (QueryDocumentSnapshot document : task.getResult()) {
objectives_id.clear();
id_route = document.getId();
if(document.exists() && document != null) {
Map<String, Object> map = document.getData();
for (Map.Entry<String, Object> entry : map.entrySet()) {
String field_name = entry.getKey() + "";
String id = document.getString(field_name) + "";
objectives_id.add(id);
}
}
routes.add(new Route(objectives, objectives_id, id_route));
}
} else {
Log.d(TAG, "Error getting documents: ", task.getException());
}
}
});
As you can see in the second code i added a Log.d ( after if (task.isSuccessful()) ) who will display the number of documents. In my case, the first query Log.d returns 3 and the second returns 0 despite the fact that i have 2 documents in there. How can i access this 2 documents ?
Thank you.
Firebase APIs are asynchronous, meaning that the onComplete() method returns immediately after it's invoked, and the callback from the Task it returns, will be called some time later. There are no guarantees about how long it will take. So it may take from a few hundred milliseconds to a few seconds before that data is available. Because that method returns immediately, the number of documents that you try to log, is not populated from the callback yet.
Basically, you're trying to use a value synchronously from an API that's asynchronous. That's not a good idea. You should handle the APIs asynchronously as intended.
A quick solve for this problem would be to move the code that queries the second collection inside the first callback (inside the onComplete() method) so-called nested queries, otherwise I recommend you see the last part of my anwser from this post in which I have explained how it can be done using a custom callback. You can also take a look at this video for a better understanding.
After i followed the steps from the video, i updated the code like this:
I have a global variable firestore created at the beginning of my class
private FirebaseFirestore firestore;
I have two methods readDataObjective and readDataRoute and two interfaces FirestoreCallback and FirestoreCallbackRoutes
readDataRoutes
private void readDataRoute(FirestoreCallbackRoute firestoreCallbackRoute){
firestore.collection("Trasee").get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) { ...
readDataObjective
private void readDataObjective(FirestoreCallback firestoreCallback){
firestore.collection("Obiective").get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
SingletonObjectivesId.getInstance().getIds().clear();
for (QueryDocumentSnapshot document : task.getResult()) { ...
Interfaces
private interface FirestoreCallback{
void onCallback(ArrayList<Objective> list);
}
private interface FirestoreCallbackRoute{
void onCallback(ArrayList<Route> list);
}
And in onCreate method i call readDataObjective and readDataRoute like this
firestore = FirebaseFirestore.getInstance();
FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder().build();
firestore.setFirestoreSettings(settings);
readDataObjective(new FirestoreCallback() {
#Override
public void onCallback(ArrayList<Objective> list) {
for(Objective item : list){
//Create plainText Object - delimiter "/~/"
String data = "Title:" + item.getTitle() + "/~/" +
............................
} else if(str.contains("Longitude:")){
obj.setLongitude(str.substring(10,str.length()));
}
start = crt + 2;
}
}
SingletonObjectivesArray.getInstance().getObjectives().add(obj);
}
readDataRoute(new FirestoreCallbackRoute() {
#Override
public void onCallback(ArrayList<Route> list) {
Log.d(TAG, 2 + " ");
ArrayList<Objective> routeObjectives = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
routeObjectives.clear();
for (int j = 0; j < SingletonObjectivesArray.getInstance().getObjectives().size(); j++){ ...
With the mention that readDataRoute is called inside readDataObjective, at the end of it.
I noticed that the problem is not only with the second query, but with the first one too. I added a new document into the first collection and after running the code, the first query return the old data ( without my new entry ).

Categories