How to add multiple values to same field in Firestore - android

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

Related

Delete a document from Firestore

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.

How to retrieve data on firebase firestore Android?

I have been searching for quite a while now and I can't seem to find anything to help me...
I want to fetch data from a firebase firestore collection that I have in reference (timeEntryTable). In the debugger, I can see that my data is accessed correctly, but when I get out of the method, it seems like everything is gone...
private void getTimes(){
float totalTime = 0;
timeEntryTable
.whereEqualTo("person", "Alexandre")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
TimeEntry timeEntry = new TimeEntry(document.getData());
times.add(timeEntry.getTime());
Log.d(TAG, document.getId() + " => " + document.getData());
}
} else {
Log.d(TAG, "Error getting documents: ", task.getException());
}
}
});
System.out.println("times = " + times);
}
In this snippet, times is a private ArrayList member and TimeEntry is a POJO that has the structure of the documents in the collection.
I can really see in the debugger that times is filled with the right data, but when I call System.out.println("times = " + times);, the value is []... Is there something I am not doing correctly?
Thank you :)
To add to the previous answer that "the first time you can use the results is inside the callback itself", move the "System.out.println("times = " + times);" line right outside underneath your for loop.
Firestore's get() operation, and all of its APIs, are asynchronous and return immediately, before the data is available. Your code continues to execute while the query completes. Some time later, the callback you attached with addOnCompleteListener will be invoked with the results of the query.
The first time you can use the results is inside the callback itself. You can't be certain that any other access to your times array will contain anything. This means that you will have to build your program around these asynchronous APIs instead of depending on line-by-line execution.

Display JsonArray from api and sort

I am trying to display data from a rest api containing a Json Array and a list of Json objects. I tried following a tutorial and was able to display the data on textview. What I actually want to do is gather the data in a Hashmap in terms of key and value pair and sort them accordingly.
public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
if(!response.isSuccessful()){
textView.setText("Code: " +response.code());
return;
}
int j=0;
List<Post> posts = response.body();
Map<Integer,String> data = new HashMap<Integer, String>();
// Iterating through post and saving data in content variable
for(Post post: posts)
{
String content ="";
//String name = post.getName();
if(!(post.getName()==(null)) && !(post.getName().equals("")))
{
data.put(post.getListid(),post.getName()); //For inserting data into hashmap
content += "ListID: " + post.getListid() + "" + "\n";
content += "Name: " + post.getName() + "" + "\n";
}
textView.append(content);
}
The current code saves the data in a content variable and displays it in the text view.
I am relatively new to using hashmap and retrofit for displaying data. I would really appreciate if someone could explain me where I am going wrong with my code. I tried printing out the data but was only able to print the last line and not the rest.
This is my Json file that I want to sort and display the data
[{"listId":2,"name":null},{"listId":2,"name":"Item 990"},{"listId":2,"name":null},{"listId":2,"name":null},{"listId":2,"name":""},{"listId":4,"name":"Item 771"},{"listId":2,"name":""}]
This is the code that I am using to displaying all my json data in textview
for(Map.Entry entry: data.entrySet())
{ textView.append(entry.getKey()+ " Value:" +entry.getValue() +"\n");}
I if understand correctly, you have a List<Post> posts that you want to sort out ? Why don't you sort the posts as you need and save them accordingly? You could just remove the post from your list if their name are null or ""

I want to store Image album in Firebase database and storage

I want to store image as first collection name and document name as album name and then image name with path. I have stored images, but not like that as I wanted. I can't create another collection without document:
I want to create this
btnSubmit.setOnClickListener(v -> {
if (edtTitle.getText().toString().isEmpty()){
Toast.makeText(this, "Please Enter Title", Toast.LENGTH_SHORT).show();
} else {
final String gelleryId =FirebaseFirestore.getInstance().
collection("Gallery").document(edtTitle.getText().toString()).getId();
progressDialog.setTitle("Uploading...");
progressDialog.show();
for(int i =0; i<arrayList.size(); i++){
StorageReference mStorageRef = FirebaseStorage.getInstance().getReference();
final StorageReference patientiamge = mStorageRef.child("Gallery").child(gelleryId).child(System.currentTimeMillis() + ".jpg");
patientiamge.putFile(arrayList.get(i))
.addOnSuccessListener(taskSnapshot -> {
if (taskSnapshot.getTask().isComplete()) {
patientiamge.getDownloadUrl().addOnSuccessListener(uri -> {
final String imageid = FirebaseFirestore.getInstance().collection("Gallery").document().getId();
GelleryListModel gelleryListModel = new GelleryListModel();
gelleryListModel.setId(imageid);
gelleryListModel.setAlbumName(edtTitle.getText().toString());
gelleryListModel.setImagePath(uri.toString());
gelleryListModel.setBranchId(String.valueOf(branchId));
Log.e("##ImageId", imageid);
FirebaseFirestore.getInstance().collection("Gallery").document("").collection(edtTitle.getText().toString()).document().set(gelleryListModel).addOnCompleteListener(task -> {
if (task.isSuccessful()) {
progressDialog.dismiss();
finish();
} else {
Toast.makeText(this, "Something went wrong", Toast.LENGTH_SHORT).show();
}
});
});
}
})
.addOnFailureListener(exception -> {
});
}
I want to create like first Collection name than album name and then image path. I have no idea how to do it and I dont know it is possible or not. I have got all entries but not as I wanted.
Using the album name as the ID of the document in your Gallery collection is easy:
FirebaseFirestore.getInstance().collection("Gallery").document(edtTitle.getText());
I recommend against using the user input for the subcollection name however. There is no client-side API to get a list of (sub)collections, so it's best to use collection names that are in your code.
I'm not sure what purpose that subcollection serves, but if it has an identifiable purpose, you'd typically name the collection after that purpose (e.g. image_ids) and then name the documents with the dynamic value you had in mind.

Firebase Multipath updates overwrites instead of update children

I am using Firebase real-time database in my Android app. For data normalization purposes, I'm saving Player's data to multiple paths.
When I save it to each path separately all works fine. But I tried to save the data using Multiple-Path update and then instead of updating existing children, this overwrites existing data (like in setValue). I read about this phenomenon somewhere but I can't get it to work as it should.
Here is the relevant snippet of my code:
public void createPlayerInFirebaseDatabse(String playerId, FirebasePlayerEntity firebasePlayerEntity, final ICreateUser listener) {
Log.e(TAG, "DBHelper.createPlayerInFirebaseDatabase");
Map<String, Object> player = new HashMap<>();
player.put(playerId, firebasePlayerEntity);
Map<String, Object> isPlayerIn = new HashMap<>();
isPlayerIn.put(playerId, true);
Map<String, Object> playerUpdates = new HashMap<>();
playerUpdates.put("players/", player);
playerUpdates.put("leagues/" + firebasePlayerEntity.getLeagueCode() + "/playersIds/", isPlayerIn);
playerUpdates.put("teams/" + firebasePlayerEntity.getTeam() + "/playersIds", isPlayerIn);
databaseReference.updateChildren(playerUpdates)
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.e(TAG, "DBHelper.createPlayerInFirebaseDatabase: onSuccess");
listener.onSuccess();
} else {
listener.onError(ErrorConsts.ERROR_CODE_DB_WRITING_FAILED);
}
}
});
It only updates the data (not overwriting) when I save data separately to each path, like this:
databaseReference.child(REF_PLAYERS).updateChildren(player);
databaseReference.child(REF_LEAGUES + "/" + firebasePlayerEntity.getLeagueCode() + "/" + REF_PLAYERS_IDS).updateChildren(isPlayerIn);
databaseReference.child(REF_TEAMS + "/" + firebasePlayerEntity.getTeam() + "/" + REF_PLAYERS_IDS).updateChildren(isPlayerIn)
I found this topic on javascript Firebase multi-location update overwriting instead of updating value
but I was wondering if anyone experienced it on Android and managed to solve this issue.
Any help would be appreciated. thanks!
A multi-location update loops over each key in the Map that you pass in, and the performs a setValue on that path. It does not do a "deep merge", so anything at any specific key in your map will be replaced. For this reason, you need to make sure that the paths in your map are to the exact data that you want to replace.
Right now your map keys point one level to high. For example your maps says to update players with $playeruid/<playerEntity>. This means that you're replacing everything under players with the data for the new player, which is not what you want. What you instead should do is tell Firebase to update players/$playeruid to <playerEntity>, so making $playeruid part of the path/key.
In code:
Map<String, Object> playerUpdates = new HashMap<>();
playerUpdates.put("players/" + playerId, firebasePlayerEntity);
playerUpdates.put("leagues/" + firebasePlayerEntity.getLeagueCode() + "/playersIds/" + playerId, true);
playerUpdates.put("teams/" + firebasePlayerEntity.getTeam() + "/playersIds/" + playerId, true);
databaseReference.updateChildren(playerUpdates)

Categories

Resources