Firebase Firestore generating two Ids in place of one - android

I am storing some data into the firebase firestore and using onComplete listener on the operation. I am Storing the ID which I generated, in a String and using it to perform further operations.
ProductRef = db.collection("Sellers").document(CityName).collection(Uid).document();
ProductID =db.collection("Sellers").document(CityName).collection(Uid).document().getId();
I am then using that generated Id to as a field in Cloud Storage and adding some images inside it and after it using the same ID I am storing the URLs of these images in the firestore but what happening is a different Id is generated in between and details are stored inside one Id and ImageUrls inside another.
My code
private void UploadDetails() {
ProductRef = db.collection("Sellers").document(CityName).collection(Uid).document();
ProductID =db.collection("Sellers").document(CityName).collection(Uid).document().getId();
HashMap<String, Object> map = new HashMap<>();
map.put("City_Name", CityName);
ProductRef.set(map, SetOptions.merge()).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
UploadingImage();
UploadingThumbnailImage();
}
});
}
private void UploadingImage() {
resized = Bitmap.createScaledBitmap(bitmap, 800, 800, true);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
resized.compress(Bitmap.CompressFormat.JPEG, 70, baos);
byte[] uploadbaos = baos.toByteArray();
ProductRef = db.collection("Sellers").document(CityName).collection(Uid).document(ProductID);
fileReference = storageReference.child(ProductID).child("1" + ProductID + ".jpg");
uploadTask = fileReference.putBytes(uploadbaos);
uploadTask.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() {
#Override
public Task<Uri> then(#NonNull Task<UploadTask.TaskSnapshot> task) throws Exception {
if (!task.isSuccessful()) {
throw task.getException();
} else if (task.isSuccessful()) {
Toast.makeText(Upload_New_Product.this, "Uploaded Successfully", Toast.LENGTH_SHORT).show();
//mProgressBar.setVisibility(View.INVISIBLE);
}
return fileReference.getDownloadUrl();
}
}).addOnCompleteListener(new OnCompleteListener<Uri>() {
#Override
public void onComplete(#NonNull Task<Uri> task) {
if (task.isSuccessful()) {
Uri downloadUri = task.getResult();
String mUri = downloadUri.toString();
// ProductRef=db.collection("Sellers").document().collection(ProductType);
ProductName = Product_Name_EditText.getText().toString();
// ProductRef = db.collection("Sellers").document(CityName).collection(Uid).document(ProductID);
//reference = FirebaseDatabase.getInstance().getReference("Users").child(fuser.getUid());
HashMap<String, Object> map = new HashMap<>();
map.put("imageURL", mUri);
//reference.updateChildren(map);
ProductRef.set(map, SetOptions.merge());
//pd.dismiss();
} else {
Toast.makeText(Upload_New_Product.this, "Failed!", Toast.LENGTH_SHORT).show();
//pd.dismiss();
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(Upload_New_Product.this, e.getMessage(), Toast.LENGTH_SHORT).show();
//pd.dismiss();
}
});
}

Every time you call document() with no parameters, you're going to get a different random document ID. Your code here is calling document() twice:
ProductRef = db.collection("Sellers").document(CityName).collection(Uid).document();
ProductID = db.collection("Sellers").document(CityName).collection(Uid).document().getId();
If you want a single random ID to reuse, just call it once:
ProductRef = db.collection("Sellers").document(CityName).collection(Uid).document();
ProductID = ProductRef.getId();

Related

Not able to store download URLs inside Firebase Firestore

I am trying to store images into Firebase Storage and then download the URI of those images from Firebase storage and then again upload those URI into the firebase firestore using a foreach loop . Images are successfully uploading into the firebase storage but Uri of only last image is going into firestore first three are failing. I created AN ARRAY LIST OF BITMAPS and then used foreach loop on it.
My Code
private void UploadingImage() {
if (bitmap != null && bitmap2 != null && bitmap3 != null && bitmap4 != null) {
StorageTask arrayUpload;
fuser = FirebaseAuth.getInstance().getCurrentUser();
ProductName = Objects.requireNonNull(Product_Name_EditText.getText()).toString();
CityName = Objects.requireNonNull(CityNameEditText.getText()).toString();
// Bitmap[] bitmaps=new Bitmap[3];
ArrayList<Bitmap> bitmapArrayList = new ArrayList<>();
bitmapArrayList.add(bitmap);
bitmapArrayList.add(bitmap2);
bitmapArrayList.add(bitmap3);
bitmapArrayList.add(bitmap4);
Bitmap bitresized;
for (Bitmap bitUpload : bitmapArrayList)
{
bitresized = Bitmap.createScaledBitmap(bitUpload, 800, 800, true);
ByteArrayOutputStream baosArray = new ByteArrayOutputStream();
bitresized.compress(Bitmap.CompressFormat.JPEG, 70, baosArray);
byte[] uploadbaosarray = baosArray.toByteArray();
i = i + 1;
fileReference = storageReference.child(ProductName).child(i + ProductName + ".jpg");
arrayUpload = fileReference.putBytes(uploadbaosarray);
arrayUpload.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() {
#Override
public Task<Uri> then(#NonNull Task<UploadTask.TaskSnapshot> task) throws Exception {
if (!task.isSuccessful()) {
throw task.getException();
} else if (task.isSuccessful()) {
Toast.makeText(Upload_New_Product.this, "Uploaded Successfully", Toast.LENGTH_SHORT).show();
//mProgressBar.setVisibility(View.INVISIBLE);
}
return fileReference.getDownloadUrl();
}
}).addOnCompleteListener(new OnCompleteListener<Uri>() {
#Override
public void onComplete(#NonNull Task<Uri> task) {
if (task.isSuccessful()) {
Uri downloadUri = task.getResult();
assert downloadUri != null;
String mUri = downloadUri.toString();
ProductName = Product_Name_EditText.getText().toString();
ProductRef = db.collection("Sellers").document(CityName).collection(Uid).document(ProductName);
HashMap<String, Object> map = new HashMap<>();
map.put("imageURL" + i, mUri);
//reference.updateChildren(map);
ProductRef.set(map, SetOptions.merge());
} else {
Toast.makeText(Upload_New_Product.this, "Failed!", Toast.LENGTH_SHORT).show();
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(Upload_New_Product.this, e.getMessage(), Toast.LENGTH_SHORT).show();
//pd.dismiss();
}
});
}
}
}
Since uploading (and getting the download URL) are asynchronous operations, the for loop completes almost immediately, and all uploads are happening in parallel after that. This means that by the time your map.put("imageURL" + i, mUri) runs, the i variable is going to be its final value.
To make the code work, you need to capture the variable of i for each iteration over the loop. A simple way to do that, is to move the code that uploads the image and stores its URL into a separate function, and pass the value of i into that function call.
Something like:
public void uploadFileAtIndex(int i) {
fileReference = storageReference.child(ProductName).child(i + ProductName + ".jpg");
arrayUpload = fileReference.putBytes(uploadbaosarray);
arrayUpload.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() {
#Override
public Task<Uri> then(#NonNull Task<UploadTask.TaskSnapshot> task) throws Exception {
if (!task.isSuccessful()) {
throw task.getException();
} else if (task.isSuccessful()) {
Toast.makeText(Upload_New_Product.this, "Uploaded Successfully", Toast.LENGTH_SHORT).show();
}
return fileReference.getDownloadUrl();
}
}).addOnCompleteListener(new OnCompleteListener<Uri>() {
#Override
public void onComplete(#NonNull Task<Uri> task) {
if (task.isSuccessful()) {
Uri downloadUri = task.getResult();
assert downloadUri != null;
String mUri = downloadUri.toString();
ProductName = Product_Name_EditText.getText().toString();
ProductRef = db.collection("Sellers").document(CityName).collection(Uid).document(ProductName);
HashMap<String, Object> map = new HashMap<>();
map.put("imageURL" + i, mUri);
ProductRef.set(map, SetOptions.merge());
} else {
Toast.makeText(Upload_New_Product.this, "Failed!", Toast.LENGTH_SHORT).show();
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(Upload_New_Product.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
And then use it in the loop with:
for (Bitmap bitUpload : bitmapArrayList) {
...
i = i + 1;
uploadFileAtIndex(i);
}
You might need to pass more of your variable to uploadFileAtIndex than I've done here, but its passing i that solves the problem you have right now.

Firestore checking if a document exist in collection

Im trying to make a code for uploading item/stock to firestore. what i want is if the Item is already registered in firestore, then recalculate the quantity. But if the item is not registered yet in firestore, system add new document to firestore.
I already make a code like below, if i try to add item that is already registered it succeed on recalculating the quantity but the problem is when i want to add new item ( that is not registered in database) it doesnt work. Can somebody fix my code.
final FirebaseFirestore db = FirebaseFirestore.getInstance();
merk = etMerk.getText().toString().trim();
type = etType.getText().toString().trim();
typemerk = type + " - " + merk;
qty = etQty.getText().toString().trim();
price = etPrice.getText().toString().trim();
date = datetime.getText().toString();
final Map<String, Object> stock = new HashMap<>();
stock.put("date", date);
stock.put("type", typemerk);
stock.put("qty", qty);
stock.put("price", price);
stock.put("merk", merk);
final FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
final CollectionReference documentReference = rootRef.collection("watchlist");
Query query = documentReference.whereEqualTo("type", typemerk);
query.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
Log.d(Tag.ITEM, document.getId() + "=>" + document.getData());
String id = document.getString("id");
String oldqty = document.getString("qty");
Integer i = Integer.parseInt(oldqty) + Integer.parseInt(qty);
String newQty = String.valueOf(i);
Map<Object, String> map = new HashMap<>();
map.put("qty", newQty);
rootRef.collection("watchlist").document(document.getId()).set(map, SetOptions.merge());
Toast.makeText(AddItemActivity.this, "Berhasil menambah stok", Toast.LENGTH_SHORT).show();
progressBar.setVisibility(View.GONE);
}
} else {
Log.d(Tag.ITEM, "not register in DB", task.getException());
Toast.makeText(AddItemActivity.this, "new item to database", Toast.LENGTH_SHORT).show();
documentReference
.add(stock)
.addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
#Override
public void onSuccess(DocumentReference documentReference) {
Toast.makeText(AddItemActivity.this, "Berhasil Memasukkan Barang ke Stok", Toast.LENGTH_SHORT).show();
progressBar.setVisibility(View.GONE);
etMerk.setText("");
etType.setText("");
etQty.setText("");
etPrice.setText("");
etMerk.setFocusable(true);
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(AddItemActivity.this, "Gagal Memasukkan stok, silahkan coba lagi.", Toast.LENGTH_SHORT).show();
progressBar.setVisibility(View.GONE);
}
});
}
}
});
}
You should check to make sure that your query returned successfully and that it's not empty. It can return an empty result if the query was processed but there was no matching result.
FirebaseFirestore db = FirebaseFirestore.getInstance();
db.collection("myCollection")
.whereEqualTo("myQuery", myQueryValue)
.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");
// Do whatever you need to do with the document
}else{
Log.d("QueryResult", "The document doesn't exist or there was an error retrieving it");
// Create the document or whatever else you need to do
}
}
});

taking data out of a realtime database

How my app adds values to realtime database:
private void uploadFile() {
if(imageUri != null){
final StorageReference fileReference = storageReference.child(System.currentTimeMillis()
+ "." + getFileExtension(imageUri));
storageTask = fileReference.putFile(imageUri);
Task<Uri> urlTask = storageTask.continueWithTask(new Continuation<UploadTask.TaskSnapshot, Task<Uri>>() {
#Override
public Task<Uri> then(#NonNull Task<UploadTask.TaskSnapshot> task) throws Exception {
if (!task.isSuccessful()) {
throw task.getException();
}
// Continue with the task to get the download URL
return fileReference.getDownloadUrl();
}
}).addOnCompleteListener(new OnCompleteListener<Uri>() {
#Override
public void onComplete(#NonNull Task<Uri> task) {
if (task.isSuccessful()) {
Uri downloadUri = task.getResult();
String miUrlOk = downloadUri.toString();
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
final String kisiId = user.getUid().toString().trim();
final String kisiAd = user.getDisplayName().toString().trim();
final String urunIsim = editurunIsim.getText().toString().trim();
final String urunYorum = editUrunYorum.getText().toString();
Map<String,Object> values = new HashMap<String,Object>();
values.put("kisiId", kisiId);
values.put("kisiAd", kisiAd);
values.put("urunAdi", urunIsim);
values.put("yorum", urunYorum);
Kullanici kullanici = new Kullanici(kisiId, kisiAd, urunIsim,urunYorum,miUrlOk);
DatabaseReference dbRef = db.getReference("Kullanici");
String key = dbRef.push().getKey();
DatabaseReference databaseReference = db.getReference("Kullanici/" + key);
databaseReference.setValue(kullanici);
String referansinAnahtari=databaseReference.getKey().toString();
databaseReference.child("urunYorum").child(referansinAnahtari).setValue(values);
Toast.makeText(getActivity(), "Upload successful", Toast.LENGTH_LONG).show();
} else {
// Handle failures
// ...
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}else{
Toast.makeText(getActivity(), "No File selected", Toast.LENGTH_SHORT).show();
}
}
How my app reads values from realtime database (a part):
kullaniciList.clear();
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
Kullanici kullaniciModel = postSnapshot.getValue(Kullanici.class);
kullaniciModel.setKey(postSnapshot.getKey());
kullaniciList.add(kullaniciModel);
}
adapterr.setOnItemClickListener(anasayfaFragment.this);
adapterr.notifyDataSetChanged();
progressCircle.setVisibility(View.INVISIBLE);
my debug is closed when I run it with debug. I think it's a logic error. How do I capture data from a realtime database?

updateChildren not updating the array of images, its overwriting the exist array(url) data firebase android

updateChildren not updating the array of images, its overwriting the exist array(url) data firebase android. I want to add some more images to existing url array in firebase.
This is my firebase structure
Blog--
pushid--
"name": xxxx
"url"
-- 0: "first image"
1: "second image"
I want to update(add some more images to existing url array . Im using updatechildren() but its overwriting the existing images
for (String photo : selectedImages) {
blogimages = new ArrayList<>();
Uri file = Uri.fromFile(new File(photo));
Bitmap bitmap = null;
try {
bitmap = decodeSampledBitmapFromUri(file, mMaxDimension, mMaxDimension);
StorageReference photoRef = mstorageReference.child("images/" + file.getLastPathSegment());
uploadTask = photoRef.putBytes(byteArray);
uploadTask.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
#Override
public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
}
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Uri downloadUrl = taskSnapshot.getDownloadUrl();
blogimages.add(downloadUrl.toString());
Map<String, Object> childUpdates = new HashMap<>();
childUpdates.put("url", blogimages);
HashMap<String, Object> params = new HashMap<>();
params.put("url", blogimages);
uploads.child(post_key).child("url").updateChildren(params).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Toast.makeText(UpdatePost.this, "Post updated..", Toast.LENGTH_LONG).show();
MainActivity.loaded = true;
Intent i = new Intent(UpdatePost.this, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(UpdatePost.this, "Failed to post the blog.. Try again later", Toast.LENGTH_LONG).show();
}
});
}
});
} catch (FileNotFoundException e) {
Log.e(TAG, "Can't find file to resize: " + e.getMessage());
FirebaseCrash.report(e);
} catch (IOException e) {
Log.e(TAG, "Error occurred during resize: " + e.getMessage());
FirebaseCrash.report(e);
}
}
That's not the way updateChildren() works. updateChildren() will completely overwrite the content for all child fields that you specify. It doesn't "push" array elements at all, or do any other array-like operations. If you want to append to an array, you're going to have to read the contents of the array from the database, then add the element, then write it back out.
Note that Firestore is different in that it has an arrayUnion operation to append non-unique array elements to an array type field.

getDownloadUrl in firebase android not working

First I take image from the user using a crop activity, I compress it and create a thumb image. I upload them on storage and save their download url in the database. For some reason, image is uploaded and link is retrieved but the thumb_image is uploaded but no link is retrieved. Please help me out. What am I doing wrong?
mprogbar.setVisibility(View.VISIBLE);
mylay.setClickable(false);
Uri resultUri= result.getUri();
final File thumb_filePath = new File(resultUri.getPath());
Bitmap thumb_bitmap = new Compressor(SettingsActivity.this).
setMaxWidth(200)
.setMaxHeight(200)
.setQuality(75)
.compressToBitmap(thumb_filePath);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
thumb_bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
final byte[] thumb_byte = baos.toByteArray();
final StorageReference filepath = mstore.child("profile_pictures").child(mcurrentuser+".jpg");
final StorageReference thumbfilepath = mstore.child("profile_pictures").child("thumbs").child(mcurrentuser+".jpg");
filepath.putFile(resultUri).addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() {
#Override
public void onComplete(#NonNull Task<UploadTask.TaskSnapshot> task) {
if(task.isSuccessful())
{
final String[] downloadurl = {""};
filepath.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
downloadurl[0] =uri.toString();
}
});
thumbfilepath.putBytes(thumb_byte).addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() {
#Override
public void onComplete(#NonNull Task<UploadTask.TaskSnapshot> thumb_task) {
if(thumb_task.isSuccessful())
{
final String[] thumb_downloadurl = {""};
thumbfilepath.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
thumb_downloadurl[0] =uri.toString();
}
});
Map mymap= new HashMap();
mymap.put("image", downloadurl[0]);
mymap.put("thumb_image", thumb_downloadurl[0]);
mdatabase.updateChildren(mymap).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful())
{
mprogbar.setVisibility(View.INVISIBLE);
mylay.setClickable(true);
Toast.makeText(SettingsActivity.this,"Profile Picture updated",
Toast.LENGTH_LONG).show();
}
}
});
}
else
{
mprogbar.setVisibility(View.INVISIBLE);
mylay.setClickable(true);
Toast.makeText(SettingsActivity.this,"Profile Picture could not be updated",
Toast.LENGTH_LONG).show();
}
}
});
}
else
{
mprogbar.setVisibility(View.INVISIBLE);
}
thumb_downloadurl[0] is just an empty string
Getting the download URL is an asynchronous operation. When you call getDownloadUrl() the Firebase SDK starts getting the download URL from the servers. When it as retrieved the download URL, it calls your onSuccess method.
While it's waiting, Firebase lets your code outside the onSuccess callback continue, as Android would otherwise show an "Application Not Responding" dialog. This is when your code with mymap.put("image", downloadurl[0]) runs, and at that point the download URL hasn't been returned from the server yet.
Any code that needs access to the download URL needs to be (called from) inside the onSuccess method. So something like this:
thumbfilepath.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
thumb_downloadurl[0] =uri.toString();
Map mymap= new HashMap();
mymap.put("image", downloadurl[0]);
mymap.put("thumb_image", thumb_downloadurl[0]);
mdatabase.updateChildren(mymap).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()){
mprogbar.setVisibility(View.INVISIBLE);
mylay.setClickable(true);
Toast.makeText(SettingsActivity.this,"Profile Picture updated",
Toast.LENGTH_LONG).show();
}
}
});
}
});
There are quite a lot of things you can do with the Task API that you're using here. I recommend reading Doug's series of blog posts on becoming a task master.

Categories

Resources