As you can see from the picture I have a child FreezerItems, and under that child I have two other childs which are randomKeys that Firebase has created by using push(). My question is, how do I specifically get the key L8i2M4wNUF5wOojaFE. Also how do I get that key into my RecyclerViewAdapter. I have tried this:
holder.mDeleteBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mDatabase = FirebaseDatabase.getInstance().getReference().child("FreezerItems");
String key = mDatabase.push().getKey();
Toast.makeText(view.getContext(), key, Toast.LENGTH_SHORT).show();
}
});
But all that ever did was show a Toast with a random key, that changes each time I click on the button
What you are doing in your code, is that you are generating each time you click on the item a new id. You are not using the one that is stored in your database. In order to use the id that was already generated once, you need to store it first. So to solve this problem, I recommend you store that random generated id provided by the push() method as a property of your model class. You database structure should look like this:
Firebase-root
|
--- FreezerItems
|
--- L8i2M4wNUF5wOojaFE
|
--- date: "3/31/2018"
|
--- name: "Ice"
|
--- freezerItemId: "L8i2M4wNUF5wOojaFE"
Then to remove that particular item, please use the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference freezerItemsRef = rootRef.child("FreezerItems");
holder.mDeleteBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
freezerItemsRef.child(freezerItems.getId()).removeValue();
}
});
In which freezerItems is the object of your model class and getId() is a public getter that returns that particular id.
Event objects should contain id, to populate id of the item when you read data populate, do like this..
for (DataSnapshot adSnapshot: dataSnapshot.getChildren()) {
Event eobj = adSnapshot.getValue(Event.class);
String key = dataSnapshot.getKey();
eobj.setItemKey(key);
mDataSet.add(eobj);
}
using the id of item you can delete it when button is clicked. Do something like this...
FirebaseDatabase.getInstance().getReference()
.child("FreezerItems").child(product.getId).removeValue()
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
//remove item from list and refresh recyclerview
mDataSet.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, mDataSet.size());
} else {
Log.d("Delete Item", "couldn't be deleted");
}
}
});
For complete example, you can see http://www.zoftino.com/firebase-realtime-database-android-example
I think it still didn't explain how do we get that id that is generated randomly.
I have many more elements when I say datasnapshot.getKey() it will return the top node but I want access nodes below this top node those are random keys. And each random key have some other values.
I belive we have to do something before .push() to get that key. Later to save in model
user---
-sSHSsdlkjjfh..
-sSHSLSHBSB...
-sSHSLKJSSKJ...
Related
I want to get data from firebase without changing my database structure because I have two condition:
When admin logins then he can see all employees data for the selected year or say year-wise.
But when employees login then they should be able to see their individual data from all the years using employee code, which is a child also (blue tick in the picture).
Below is my database structure:
The child marked in red is unknown in case of employee's access and the blue tick denotes an employee who may be present in every year.
All I want is to achieve the 2nd condition. But I am unable to get the data.
Here is my code:
private void retrieveData() {
final String shift = kvName.getText().toString();
final String employeeCode = empCode.getText().toString();
dbRef.child("Apar").child(shift);
dbRef.orderByChild(employeeCode).equalTo(employeeCode).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot datas1 : dataSnapshot.getChildren()) {
for (DataSnapshot datas2 : datas1.getChildren()) {
// String aparGrading= datas2.getKey(); //unable to figure out how to get
// Toast.makeText(Apar.this, aparGrading, Toast.LENGTH_LONG).show();
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
Your current data structure makes it easy to find the information for all employees for a specific year. It does however not make it easy to find the information for a specific employee across all years.
To do the latter, you have two options:
Check each year for the presence of a node for that employee ID.
Add an additional data structure that maps from each employee ID to the years for which they have data, and then load each year's data for that employee individually
For more on this, also see:
Many to Many relationship in Firebase
Firebase query if child of child contains a value
Firebase Query Double Nested
Speed up fetching posts for my social network app by using query instead of observing a single event repeatedly, to learn why the second approach is not as slow as you may think.
After reading the various answers on this topic linked above by Mr. #Frank van Puffelen and spending some times over it, the problem is finally solved now without changing my database structure.
Below is screenshot of the result which I wanted:
Here is my modified and working code :
private void retrieveData() {
final String shift = kvName.getText().toString();
final String employeeCode = empCode.getText().toString();
final DatabaseReference aparRef = dbRef.child("Apar").child(shift);
aparRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
list = new ArrayList<>();
if (dataSnapshot.exists()) {
for (DataSnapshot dataS1 : dataSnapshot.getChildren()) {
if (dataS1.hasChild(employeeCode)) {
AparData aparData = dataS1.child(employeeCode).getValue(AparData.class);
list.add(aparData);
rvAPAR.setHasFixedSize(true);
rvAPAR.setLayoutManager(new LinearLayoutManager(Apar.this));
rvAPAR.setItemAnimator(new DefaultItemAnimator());
aparAdapter = new AparAdapter(Apar.this, list);
rvAPAR.setAdapter(aparAdapter);
} else {
Toast.makeText(Apar.this, "No Data Found!!", Toast.LENGTH_SHORT).show();
}
}
} else {
Toast.makeText(Apar.this, "Not Data Found!!", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
Initially, I wrote a code to store the value in Firebase realtime database.
mDbRef = mDatabase.getReference().child("Users");
mDbRef.child("name").setValue(rname);
mDbRef.child("email").setValue(remail);
The child value was stored under its Uid in 'Users' child.
Then I changed the code to
String name = userName.getText().toString();
mDbRef = mDatabase.getReference().child("Users").child(name);
mDbRef.child("name").setValue(rname);
mDbRef.child("email").setValue(remail);
Now, the child value was stored under its name in 'Users' child.
Now I have two issues,
If I add same name with different sub child values, it was not accepted. How to rectify it?
I wrote the following code to check user before starting an activity.
public void checkUserExists () {
final String user_id = Objects.requireNonNull(uAuth.getCurrentUser()).getUid();
mDbRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.hasChild(user_id)) {
startActivity(new Intent (LoginActivity.this, HomeActivity.class));
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
The new Intent activity was working fine when the child was under Uid. When it was changed to 'name' in lieu of Uid, the intent activity doesn't start. But if I restart the app after closing it, it directly goes to Home activity. What should be done to rectify the issue?
May I suggest something like that:
String key = mDatabase.child("users").push().getKey();
// key is generated by Firebase and is unique
mDbRef = mDatabase.getReference().child("users").child(key);
mDbRef.child("name").setValue(rname);
mDbRef.child("email").setValue(remail);
And check the documentation
happy to help!
i want to check id duplication
i want to make id duplication check code.
so i get the id which is typed from user by using sid = id.getText().toString().trim();
and then make json trees FirebaseDatabase.getInstance().getReference().child("users").child("id").setValue("add");
by using child() method ...
and put the value using setvalue() method.
because it was not possible to use ondatachange() method... (i think this method only works when there is data so i put some no useful data) i will remove the value which is in setvalue() method later (is there another method that can be used even though there is no change... i need to check the db contents)
anyway if (data.getValue()==sid) this part
i thought it can check the id ...
but it does not work
12-25 21:06:00.771 6700-6700/com.example.pc.login D/myTag: {id=add}
android log looks like this... id is the child part... and the add is the value that i put
that is the result of the getvalue() method...
summary
:
1. how can i put the id from users to the firebase db
2. how can i get the only id value except child part
when i use getvalue() method. it takes child name and the value that i put
so if the id is exist ...user made ... user should write another...
if not... the firebase db store the id user made...
thank you for reading ... help me...
idcheckbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//store the id user created
sid = id.getText().toString().trim();
FirebaseDatabase.getInstance().getReference().child("users").child("id").setValue("add");
FirebaseDatabase.getInstance().getReference().addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot data: dataSnapshot.getChildren()){
if (data.getValue()==sid) {
Log.d("myTag",""+dataSnapshot.getChildren());
Toast.makeText(MainActivity.this, "aleady exists",Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "you can use this id",Toast.LENGTH_SHORT).show();
FirebaseDatabase.getInstance().getReference().child("users").child("id").setValue(sid);
Log.d("myTag",""+data.getValue());
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
});
because it was not possible to use ondatachange() method... (i think this method only works when there is data so i put some no useful data)
No onDataChange(DataSnapshot dataSnapshot) method is triggered once when the listener is attached, whether there is data or NOT.
If the database path where the ValueEventListener is attached is empty/null/non-existent than dataSnapshot.exits() will return false.
Hence here can be your final code:
idcheckbtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sid = id.getText().toString().trim();
// No need to store the id user created
// FirebaseDatabase.getInstance().getReference().child("users").child("id").setValue("add");
FirebaseDatabase.getInstance().getReference().child(sid).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
// sid already exists
} else {
// sid does not exists already
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
});
By the way your Firebase Database will look something like this:
{
"sid_1": "...",
"sid_2": "..."
}
I am having trouble trying to query some information in my database, the following picture resumes what information I am trying to fetch, I am trying to get the "productId"
This is how my database looks like:
https://i.stack.imgur.com/JhJNs.png
In fact, I am trying to get this value in order to put a condition on it. I am trying to send a notification, ONLY if the productId = 02 is selected, here is my code
if (request.getFoods().isEmpty()) {
Toast.makeText(Cart.this, "Your cart is empty", Toast.LENGTH_SHORT).show();
} else{
final DatabaseReference tokens = FirebaseDatabase.getInstance().getReference("Requests");
final Query data = tokens.orderByChild("productId").equalTo("02"); // get all node with isServerToken
data.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String order_number = String.valueOf(System.currentTimeMillis());
requests.child(order_number).setValue(request);
sendNotificationOrder(order_number);
Toast.makeText(Cart.this, "Notification sent", Toast.LENGTH_SHORT).show();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Thank you for the help!
Actually your above code would not work with orderByChild() like that. If you have multiple items in your foods node with their parent nodes being 0, 1 and so on, and you want to check their productId, then only this can be done.
For this, you'd have to make the parent child foods and call orderByChild() on it, for productId. The code would look something like this:
final DatabaseReference tokens = FirebaseDatabase.getInstance().getReference("Requests").child(id).child("foods");
tokens.orderByChild("productId").equalTo("02").addSingleValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// do what you want
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Do something for errors, don't ignore
}
However, if you have database structure with different parent nodes and there is one more median node between it and the node you want to retrieve data from, then that won't work with a code like above.
Learn more about how to make a database structure suitable for orderByChild() here.
I have a query that looks like this:
Query first = ref.orderBy("name", Query.Direction.ASCENDING).limit(10);
This is how I display the data to my RecyclerView.
firestoreRecyclerOptions = new FirestoreRecyclerOptions.Builder<ModelClass>().setQuery(query, ModelClass.class).build();
myFirestoreRecyclerAdapter = new MyFirestoreRecyclerAdapter(firestoreRecyclerOptions);
recyclerView.setAdapter(myFirestoreRecyclerAdapter);
I'm trying to use pagination as specified in here and I cannot solve it.
first.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot documentSnapshots) {
DocumentSnapshot lastVisible = documentSnapshots.getDocuments().get(documentSnapshots.size() - 1);
Query second = ref.orderBy("name", Query.Direction.ASCENDING).startAfter(lastVisible).limit(10);
//Create a firestoreRecyclerOptions and setting the adapter
}
});
Is there a way to paginate queries by combining query cursors using FirestoreRecyclerAdapter? Is this even possible?
As #FrankvanPuffelen already answered in an earlier question of yours, you cannot achieve that because in your case, you should pass 2 different queries (first and second) to a single adapter, which is not possible with FirestoreRecyclerAdapter. You can either use the first query or the second with a single instance of your adapter.
A solution would be to create two different lists, containing the results from each query and combine them. Then you can pass the resulting list to another adapter, let's say an ArrayAdapter and then display the results into a ListView or even better in a RecyclerView. The problem in this case is that you will not be able to use the real-time features that the FirestoreRecyclerAdapter class provides but this approach will solve your problem.
Edit:
According to your request from the comment section, I'll give you an example on how to paginate a query on button click in the easiest way, using a ListView and an ArrayAdapter. You can achieve the same thing also using a RecyclerView when scrolling down. But to keep things simple, let's assume we have a ListView and a Button and we want to load more items to the list on every button click. For that, let's define first the views :
ListView listView = findViewById(R.id.list_view);
Button button = findViewById(R.id.button);
Let's assume we have a database structure that looks like this:
Firestore-root
|
--- products (collection)
|
--- productId (document)
|
--- productName: "Product Name"
And a model class that looks like this:
public class ProductModel {
private String productName;
public ProductModel() {}
public ProductModel(String productName) {this.productName = productName;}
public String getProductName() {return productName;}
#Override
public String toString() { return productName; }
}
Now, let's define a query with the limit set to 3.
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference productsRef = rootRef.collection("products");
Query firstQuery = productsRef.orderBy("productName", Query.Direction.ASCENDING).limit(3);
This means that on every button click, we'll load 3 more items. And now, here is the code that does the magic:
firstQuery.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
List<ProductModel> list = new ArrayList<>();
for (DocumentSnapshot document : task.getResult()) {
ProductModel productModel = document.toObject(ProductModel.class);
list.add(productModel);
}
ArrayAdapter<ProductModel> arrayAdapter = new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, list);
listView.setAdapter(arrayAdapter);
lastVisible = task.getResult().getDocuments().get(task.getResult().size() - 1);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Query nextQuery = productsRef.orderBy("productName", Query.Direction.ASCENDING).startAfter(lastVisible).limit(3);
nextQuery.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> t) {
if (t.isSuccessful()) {
for (DocumentSnapshot d : t.getResult()) {
ProductModel productModel = d.toObject(ProductModel.class);
list.add(productModel);
}
arrayAdapter.notifyDataSetChanged();
lastVisible = t.getResult().getDocuments().get(t.getResult().size() - 1);
}
}
});
}
});
}
}
});
In which lastVisible is a DocumentSnapshot object that represents the last visibile item from the query. In this case, every third one and it is declared as gloabl variable:
private DocumentSnapshot lastVisible;
Edit2:
Here you have also the solution on how you can get the data from your Firestore database and display it in smaller chunks in a RecyclerView when user scrolls.
A possible approach is save the push keys of each item in a separate node.
Then fetch all keys from that node to an array list or something ..
Then based on your pagination number fetch the keys from this array List and use orderByKey Query and startAt and LimitToFirst queries combined to make the pagination algorithm