I am trying to delete a document from a collection called "photo" but it doesn't work, there is no OnFailureException message as OnSuccess Toast is shown but the document still remain in the Firestore :(
Structure of the firestore:
This is the codes I use to delete the document:
Photo photo = (Photo) getIntent().getSerializableExtra("photo");
FirebaseFirestore db = FirebaseFirestore.getInstance();
String userId = mAuth.getCurrentUser().getUid();
CollectionReference photoRef = db.collection("main").document(userId).collection("photo");
DocumentReference document = photoRef.document(photo.getId());
String currentDocumentID = document.getId();
photoRef.document(currentDocumentID).delete().addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(ViewPhotoActivity.this, "Entry Deleted", Toast.LENGTH_SHORT).show();
startActivity(new Intent(ViewPhotoActivity.this, PhotoActivity.class));
finish();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(ViewPhotoActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
}
});
I am writing the answer from speculation as there is not enough information as to how you are creating the document.
DocumentReference document = photoRef.document(photo.getId());
In the above line you are creating a reference to a document with photo id. Looking at the document data it seems the photo id is not same as the document id.
Therefore when you create the above reference- you are not referring to the existing document with id="2BMG3..." rather a NEW document with id="jYBPX..."
String currentDocumentID = document.getId();
photoRef.document(currentDocumentID).delete()
How you can fix it depends on how you want to save/create the documents. One way could be to create the documents in photo collection with id= photo id in the first place.
For example, when creating, you could create the document reference as following:
CollectionReference photoRef = db.collection("main")
.document(userId)
.collection("photo")
.document(photo.getId());
And then set the data as:
photoRef.set(photo);
That'd set the data to a document you have created with id=photo id.
These examples can be improved if you show how you're adding documents to photo collection now. If you've been using .colection('photo').add() or .collection.document().set(photo) then the created document would have an auto-generated id different from the photo id.
I am sure there are several ways to do this which includes the answer I received above, the getID method is a little confusing to me as it doesn't work sometimes or give me a null exception, so I changed my code and use a simpler way, which is to create a unique ID for each document when they are being created, then set the document Id with that unique ID so I could retrieve them easily, for this case, I created the ID by combining the title and 6 random digits.
When creating the document, I added a unique ID field for each document:
//set a unique ID for each photo
String randomSixNumbers = getRandomNumberString();
String photoId = (title.toLowerCase() + randomSixNumbers).replace(" ", "").trim();
//set ID to new object
Photo photo = new Photo(photoId, title, photoDescription, filePath, datePhoto);
//add object to firestore and set document ID as the uniqueID instead of the default auto-generated documentID
photoRef.document(photoId).set(photo).addOnSuccessListener(...
delete the document using the unique ID:
photoRef.document(photo.getId()).delete().addOnSuccessListener(...
For now, this process seems okay, though I am not sure if it is a good practice or not? If not, could someone point out the downside/fault of this method?
And I noticed that I have to use intent to get the data passing from last activity to get the object data in current activity.
Related
I am doing a project for school - android app which registers users to realtime database after it checks if there's a corresponding card number and phone number in a different database in Firestore. At the moment it verifies only the first document, but it wouldn't find the fields if I search for them in other documents.
This is the method I use:
public void checkIfCardExists() {
Query query = cardInfo.whereEqualTo("CardNo", cardNumber)
.whereEqualTo("Phone", userPhone);
query.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
boolean documentExists;
if (task.isSuccessful()) {
Log.d("QueryResult", "Is query result empty: " + task.getResult().isEmpty());
documentExists = !task.getResult().isEmpty();
}else {
Log.e("QueryResult", "Error getting documents.", task.getException());
documentExists = false;
}
if(documentExists) {
Log.d("QueryResult", "The document exists");
Toast.makeText(com.example.transportticket.RegistrationLeap.this, "Card number found",
Toast.LENGTH_SHORT).show();
userLeap = new UserLeap(userEmail, userPass, userName, userSurname, cardNumber, userPhone);
registerUserLeap(userEmail, userPass);
startActivity(new Intent(RegistrationLeap.this, Empty.class));
}else{
Log.d("QueryResult", "The document doesn't exist or there was an error retrieving it");
Toast.makeText(com.example.transportticket.RegistrationLeap.this, "Card number not found",
Toast.LENGTH_SHORT).show();
startActivity(new Intent(RegistrationLeap.this, Empty.class));
}
}
});
}
And this is how my Firestore database looks like
Firestore database
I added a photo to clarify about finding the first document
If you are using the following line of code:
Query query = cardInfo.whereEqualTo("CardNo", cardNumber)
.whereEqualTo("Phone", userPhone);
It means that you are telling Firestore to return all documents where the CardNo property holds the value of cardNumber AND the Phone property holds the value of userPhone. So if in your collection only one document satisfies this constraint, a single document will be returned. The other documents won't exist in the results. What you are doing now, is called filtering. However, if you want to get all documents, then you should remove both whereEqualTo() calls or directly use cardInfo which is a CollectionReference object. In this way, you aren't filtering anything. A CollectionReference object is basically a Query without any filters.
So using the last solution you can get all documents and you can also create the filtering on the client. This is not a recommended approach because getting all documents, will be very costly. For instance, if you have in your collection 1000 documents, you'll pay 1000 read operations to have them. So it's up to you to decide which one is better for you.
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.
Firestore database image
Hello, I just tried to use Firestore. I had some problem when getting document id.
The question is, I want to get a document id (red box) which has value (blue box) in it.
I use the following query:
collection("mychannel").whereEqualTo("74wRU4xHrcV9oWAXEkKeRNp41c53")
But did not give results.
Thanks!
As in the official documentation:
Although Cloud Firestore can store arrays, it does not support querying array members or updating single array elements.
So there is no way in which you can use the following query:
collection("mychannel").whereEqualTo("74wRU4xHrcV9oWAXEkKeRNp41c53")
If you only want to get the entire userId array you need to iterate over a Map like this:
collection("mychannel").document("1fReXb8pgQvJzFdzpkSy").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, Object> map = document.getData();
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getKey().equals("userId")) {
Log.d("TAG", entry.getValue().toString());
}
}
}
}
}
});
But note, even if userId object is stored in the database as an array, entry.getValue() returns an ArrayList, not an array.
So the output will be:
[74wRU4xHrcV9oWAXEkKeRNp41c53]
A better approach will be if you consider this alternative database structure, where each user id is the key in a map and all values are true:
userId: {
"74wRU4xHrcV9oWAXEkKeRNp41c53": true,
"AdwF...": true,
"YsHs...": true
}
This question is answered here: Firestore: Query by item in array of document
In summary, don't use arrays to store data in Firestore as the query you are trying to do is not available yet (remember it is still in beta). You should use a Map instead.
I am trying to add multiple image Uri's to the same field in Firestore.
.
I have been trying several methods, instead of adding image Uris to the same field it creates multiple documents in fire store. I need help.
for (int i = 0; i < imageUris.size(); i++) {
Toast.makeText(getApplicationContext(), "ROUND:" + i, Toast.LENGTH_SHORT).show();
imgUri = imageUris.get(i);
imageFilesPath = storageReference.child("Ads_images" + "/" + "Ad_" + UUID.randomUUID().toString() + ".jpg");
imageFilesPath.putFile(imgUri).addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() {
#Override
public void onComplete(#NonNull Task<UploadTask.TaskSnapshot> task) {
if (task.isSuccessful() && task != null) {
LIST.add(task.getResult().getDownloadUrl().toString());
Log.e(TAG, "List inside"+LIST.size());
Map<String, Object> adMap = new HashMap<>();
adMap.put("user_id", user_id);
adMap.put("description", "Small description is shown here");
adMap.put("imageUris", Arrays.asList(LIST.get(0)));
firebaseFirestore.collection("Ads").add(adMap);
}else {
}
}
});
Every time you call add() on a collection, Firestore creates a new document. Since you now call add() after uploading each file, you get a separate document for each file. If you want to add your URL to an existing document, you must get a DocumentReference to that document and update it.
firebaseFirestore.collection("Ads").doc("v1ys3tyQ7vhHLD0ietAw").update(adMap);
To add a URL to the imageUris array, you will need to first load the current contents of that array (to determine what index to add the item to). This read-to-update sequence is somewhat inefficient at scale. If that matters to your app, you might want to consider storing the URLs in a map inside the document instead, or storing them in a subcollection under the document.
Map<String,Object> imageUrl = new HashMap<>();
imageUrl.put("ImageUrl", imageList);
firebaseFirestore.collection("ImageDetails").document(userId)
.set(imageUrl,SetOptions.merge());
this worked fine for me too, but i passed the list separately once all the list items were added,here imageUrl is my map object and imageList is an arraylist for storing generated image uri download links.
Also by any chance could I get the look at the code at how you fetched back all those image uri
It is said that we can retrieve our data if we are having objectId for that particular row, but it is auto generated and we cant insert it while setting data , so how to get data if i am not having object id , or any other means so that i can set objectId on my means.
Code is here as in comment:
ParseObject gameScore = new ParseObject("My Parse File");
String objectId = gameScore.getObjectId();
ObjectId doesnt't exist until a save operation is completed.
ParseObject gameScore = new ParseObject("My Parse File");
To retrieve the object id you need to save the object and register for the save callback.
gameScore.saveInBackground(new SaveCallback <ParseObject>() {
public void done(ParseException e) {
if (e == null) {
// Success!
String objectId = gameScore.getObjectId();
} else {
// Failure!
}
}
});
ObjectId can be retrieved from the original ParseObject(gameScore) once the done save callback is fired.
You can use this for getting current user object id
ParseUser pUser= ParseUser.getCurrentUser();
String objId= pUser.getObjectId();
not sure if this will apply to android , but I was trying to retreive the objectid, but for an entry that is already created. I did something like this and it worked.
ParseObject gameScore = new ParseObject("My Parse File");
var obId = gameScore.id;
Got it from the Javascript docs on Parse.com
The three special values are provided as properties:
var objectId = gameScore.id;
var updatedAt = gameScore.updatedAt;
var createdAt = gameScore.createdAt;
You can't unfortunately use the ObjectId until the object's been saved. I'm having this same problem now. The only solution I can think of, and posted a similar question relating to it here
My solution would be to make a tempId on the object and refer to that locally until it has an actual ObjectId, perhaps using a saveInBackground or saveEventually() callback to set other objects relating to it, to it's newly created ObjectId instead of it's old temp one.. when it's made available
It takes times for your values to be stored in table. Use this to get ObjectId
gameScore.saveInBackground(new SaveCallback() {
public void done(ParseException e) {
if (e == null) {
// Saved successfully.
Log.d("main", "User update saved!");
Log.d("main", "ObjectId "+gameScore.getObjectId());
} else {
// The save failed.
Log.d("main", "User update error: " + e);
}
}
});
In case you're handling the thread yourself:
First save:
gameScore.save();
Then you'll be able to access the id:
String parseId = gameScore.getObjectId();