I've been trying to make this work from
How to delete firebase data after "n" days
but it's not working for me.
Here's what I'm doing,
In my "A" activity, I have a button that will save this chunk of data, with a 'timeStamp' child which holds the timestamp value.
(.setValue(ServerValue.TIMESTAMP);)
After pressing the button, it saves the data successfully. Then, it starts the next activity, where we wait.
But instead of deleting after '30' days, it deletes it straight away.
I have a method that works exactly like the answer by Frank
long cutoff = new Date().getTime() - TimeUnit.MILLISECONDS.convert(30, TimeUnit.DAYS);
Query oldBug = mDatabase.orderByChild("timeStamp").endAt(cutoff);
oldBug.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
for (DataSnapshot itemSnapshot: snapshot.getChildren()) {
itemSnapshot.getRef().removeValue();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
But it's not deleting it after some time, as soon as it is posted.
Thank you.
EDIT:
The orderByChild() sorting method is very forgiving. The children being sorted are not required to have a member with the specified field name. The documentation explains that those children are assigned a null value and appear first in the sort. Thus, if the reference used to create a query is incorrectly located, the query doesn't fail and instead will typically return all the children of that location.
You created your oldBug query using mDatabase where:
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference();
This is one level too high. It should be:
Query oldBug = mDatabase.child("Users").orderByChild("timeStamp").endAt(cutoff);
I think you might consider making a new child item that has a timestamp and date so that you can reference back to it when doing a query for the date and time. This way you don't have to worry about incorrect values and you can ensure you are deleting the correct data. I hope this helps.
Related
I am designing a simple basic chat app using firebase real time database and i've designed everything well, however, i'm facing one sllight issue. My chats keep duplicating themselves on the inbox page (the page whrere the chats are laid out for a user to select which chat he wants to open and start talking).
I've attached an image of what i mean below.
Screenshot of the phone screen
The code i am using to get the chats and display them in the recycler view is given below. I have a directory called Conversations in my DB that saves a user's Id and under it, theres a child of each and every person he chats wit, under which is the last message and a seen boolean.
Database Structure
The code is given below
convoref = FirebaseDatabase.getInstance().getReference().child("Conversations").child(currentUid);
and then..
public void getConvoIds() {
convoref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for(DataSnapshot convo : dataSnapshot.getChildren()){
boolean isMessageSeen = false;
String lastMessage = "";
if(convo.child("seen").getValue() != null) {
isMessageSeen = (boolean) convo.child("seen").getValue();
}else{
Log.i("nolastseen", "location is null");
}
if(convo.child("lastMessage").getValue() != null) {
lastMessage = convo.child("lastMessage").getValue().toString();
}else{
Log.i("nolastMessage", "location is null");
}
Log.i ("the_convo_partner_key", convo.getKey());
Log.i ("lastseenmessage", lastMessage);
Log.i ("seenstate", String.valueOf(isMessageSeen));
FetchConvoInfo(convo.getKey(), isMessageSeen, lastMessage );
}
}
}
the fetch convo information functuion is below
public void FetchConvoInfo(final String key, final boolean isMessageSeen, final String lastMessage){
FirebaseDatabase.getInstance().getReference().child("Users").child(key).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
boolean chatExists = false;
String username = "";
String thumbnail = "";
String chatPartner;
chatPartner = key;
if(dataSnapshot.child("username").exists()){
username = dataSnapshot.child("username").getValue().toString();
}
if(dataSnapshot.child("thumbnail").exists()){
thumbnail = dataSnapshot.child("thumbnail").getValue().toString();
}
ConvoClass obj= new ConvoClass(chatPartner, username, thumbnail, isMessageSeen, lastMessage);
resultConvos.add(obj);
mConvoAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
Any help would be greatly appreciated. i cant seem to figure out why the chat duplicates.
In your onDataChanged method, you are going through every child of the dataSnapshot. Each child of the data snapshot indicates a particular conversation of that particular currentUid guy. So when you are going through every child of the dataSnapshot you are adding all its children to the listview or recyclerview(I don't know what you are using. But you are adding it to the adapter). So you are adding the old data again and again whenever some new data must be added. Hence-duplicate data.
There are two common solutions.
The first is naive method. Do what you are doing right now. But while adding an item (chat, you will call it in your case, I think) to the adapter, check if it is already present in the container resultConvos. That will prevent you from adding duplicate chats. I am sure it is obvious to you also why this method is inefficient. You are unnecessarily having to go through every conversation of a person. It takes O(n) time for just adding one item.
The second method is the recommended method. Remove all the code of ValueEventListener. Instead use ChildEventListener. I don't know if you are aware of it. Check this.
ChildEventListener has mainly 4 methods instead of onDataChanged. Among that, what you require here is onChildAdded. Just like your onDataChanged, it has one argument- a data snapshot. But this data snapshot contains only the newly added child, whereas the data snapshot in onDataChanged contains the whole data of the conversations of that particular user (that means the whole list). So using the data snapshot provided by onChildAdded you can directly add only that chat to the adapter, which takes O(1) time.
For more about ChildEventListener, read that link I attached
i want to make this type of collection in my firestore
where chatRooms will be my collection name, combination of myUid and opponentsUid will be my sub-collection in which different documents will be placed. My problem is i want to check if my collection contains sub-collection named myUid_opponentsUid or opponentsUid_myUid and i am not able to search a best query for doing this.
All i know is that we can fetch the whole list and then check if it contains the specific room or not, but its a lengthy process, so i want to better method for it.
Thanks in advance.
There are a few misconceptions in your question to clear up first:
In Firestore collections don't really exist as distinct entities. It's the documents inside a collection that cause it to become visible.
Also, collections can only contain documents, which in turn can contain collections, but the structure must alternate, so you can't have a collection called chatRooms that contains a collection myUid_opponentUid. Inside chatRooms there must be a document.
So if chat rooms contain messages, a straightforward way to do what you want is to create a document that represents that chatRoom. Then within that create a subcollection for the messages.
If you sort the UIDs before creating the composite chatRoom key you can then test whether or not the chat room exists by using a single get(). The structure would look like this:
chatRooms/(uid-pair)/messages/(message-id)
Note that you don't actually need to store anything at the chatRoom/(uid-pair) level to create children at the messages level: you can just create new messages and listen directly.
Try to Read Total Number of child .! Hope this thing may helps you.and if you want to implement your own api then try using Firebase Functions..and last thing I want to add is that if You want to add get Count without reading number of child you have to implement one method that getChildCount before storing data and then append them with key like JiGh_31GA20JabpZBfa,1` and only read keys and then use comma separator and you will get your result that this parent contains child or not.?
DatabaseReference myRef = database.getReference();
//You can use the single or the value.. depending if you want to keep track
String id= UUID.randomUUID().toString();//randomID for task
Object object=new Object ();
public int chidcount(String child){
string childcount="0";
//You can use the single or the value.. depending if you want to keep track
myRef.child(child).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snap: dataSnapshot.getChildren()) {
childcount=snap.getChildrenCount();
Log.e(snap.getKey(),snap.getChildrenCount() + "");
}
addvalue(childcount);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private addvalue(String childcount){
object=setid(id);
object=setname("name");
getchildCount("object");
mdatabaseRef.child("rating").child(manager.getId()+childcount).child(currentEmployee.getId()).child(id).setValue(rating);}
I know I am late.
Posting for future users.
Try this:
DocumentReference datab = db.collection("collection_name").document("Doc_name");
datab.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if(documentSnapshot.contains("field_name"))
{
Toast.makeText(YourActivity.this, "Child exixts.", Toast.LENGTH_SHORT).show();
}
else
Toast.makeText(YourActivity.this, "Doesnt exits.", Toast.LENGTH_SHORT).show();
}
});
For Firebase Firestore to check whether the document has entries (fields), Use this command
firebaseFirestore.collection("Users").document(userId)
.addSnapshotListener {
documentSnapshot, _ ->
if (documentSnapshot!!.contains("name")) {
Log.i("Name", "Name exists")
} else {
Log.i("Name", "Name doesn't exists")
}
}
I have a ListView that each row contains several EditText and a save Button.
In the ShowOrder activty i'm getting the data from Firebase
public void getItemsOrderDetails(final String key){
orderDetailsRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
arrayLength = dataSnapshot.getChildrenCount();
String itemN="", discription="", qty="", pcsCtn="", ctnWt="", compileStatus="", palletN="", ttlCtn="";
if(!key.equals("costumerName") && !key.equals("dateOfDelivery") && !key.equals("dateOfOrder") && !key.equals("orderN") && !key.equals("remarks") && !key.equals("status")){
if(dataSnapshot.child(key).hasChild("itemNumber")){
itemN= dataSnapshot.child(key).child("itemNumber").getValue().toString();
}
...
... {downloading all data}
...
itemsClass= new ItemsClass(orderNumber, itemN, discription, pcsCtn, ttlCtn, ctnWt, qty, compileStatus, palletN );
itemsClassArrayList.add(itemsClass);
adapter.notifyDataSetChanged();
}
I'm showing all the data at the adapter , and problem is when I want to update the data onChildAdded is beeing triggered multiple times.
This is the update part in the Adapter:
private void updateData(ViewHolder vh, String orderN){
showOrder.itemsClassArrayList.clear();
updateStatus="idle";
ordersRef.child(orderNumber).child(itemN).child("palletNo").setValue(pallete);
ordersRef.child(orderNumber).child(itemN).child("pcsPizza").setValue(untCtn);
ordersRef.child(orderNumber).child(itemN).child("compileStatus").setValue(collected);
ordersRef.child(orderNumber).child(itemN).child("drink").setValue(ctnWt);
ordersRef.child(orderNumber).child(itemN).child("ttlWt").setValue(pltWt);
ordersRef.child(orderNumber).child(itemN).child("ttl").setValue(ttlCtn);
updateStatus= "update";
//showOrder.adapter.clear();
}
What I discovered is that if i'm updating only one child (Deleting all the others) the onChildAdded will be update only once.
So i don't understand how can i update all with out multiple Updating, if anyone as an idea.
Thank you
This might not be a complete solution to your issue, but a few things struck me right away:
You can (and should) load and store complete Objects in your database, so instead of reading and writing each child (e.g. of your ItemsClass object) separately, you should store your item like so:
ordersRef.child(orderNumber).child(itemN).setValue(myItem)
where myItem is an instance of ItemsClass that has been populated with data before.
In a similar way, loading data should be done like so (depending on where orderDetailsRef points to! see below):
public void onDataChange(DataSnapshot dataSnapshot) {
ItemsClass items = dataSnapshot.getValue(ItemsClass.class);
}
Also, you mention onChildAdded getting called multiple times, yet in your example you are using a ValueEventListener's onDataChange method.
Could you give a complete code sample? The one you posted is lacking relevant parts of your solution. And let me know how your code behaves when you load and save the way I suggested.
I have the following data structure on firebase for the user MF0qeRA4p7djfjgXxqwFOck3m6p02. I want to get the value of item3 to populate a single field into the User interface on an Android App. I have been looking through samples on Stackoverflow, but all I have found are outdated and do not work with the current version of firebase. I'm new to firebase completely and this is my first app on android. I've got the oncreate user method to populate the users email address and add the 4 item fields, but retrieving the data I'm completely lost and I am not sure where to even begin.
-Users
---MF0qeRA4p7djfjgXxqwFOck3m6p02
------item1:"1"
------item2:"2"
------item3:"3"
------item4:"4"
According to what I can identify is, you are facing problem retrieving data from this reference. Here is the code:
final DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("Users");
databaseReference.child("MF0qeRA4p7djfjgXxqwFOck3m6p02").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String, Object> map=(Map<String, Object>)dataSnapshot.getValue();
String item3=(String)map.get("item3");
display(item3);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Hope this helps.
You can create a custom model and inside you can insert elements. Something like this:
public class Item {
private List<Object> ojects;
}
There you can save instance of Item on database. In this case you have more controll. Other case is to use push() method, that will generate a new encoded key, something like this:
mDatabase.child("items").push().put(new Object());
Working on an Android app that is using the new Firebase Database framework. It has data objects that are modeled like this:
Where the Top parent (1234-4321) is the 'chat room', the data object are the 'chat messages', and the numbered items (0, 1, 2) are the 'individual message'.
I am able to get the entire Database without any trouble and read it via listeners:
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference();
myRef.addChildEventListener(this);
myRef.addValueEventListener(this);
And I am able to get a single child in this fashion:
FirebaseDatabase database = FirebaseDatabase.getInstance();
String id = "1234-4321";
DatabaseReference myRef = database.getReference().child(id);
myRef.addChildEventListener(this);
myRef.addValueEventListener(this);
But I cannot for the life of me figure out how to get multiple objects of the same type. What I mean is, a user will be able to get More than one chat room (IE, both '1234-4321' and '1234-4432'), but the only way I can see to do this is either to:
1) loop through the onChildAdded or onDataChange listeners, separate out the items by matching the String ids, and updating them. This is, however, extremely inefficient as I am parsing the entire Database, which could be quite large
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if(dataSnapshot != null){
try {
ChatObjectV2 objectV2 = (ChatObjectV2) dataSnapshot.getValue();
//Check here for ids and loop through everything
} catch (Exception e){
e.printStackTrace();
}
}
}
or
2) To add a specific child, but if I try to add more children it is going 'deeper' into the nested object when I want it to go 'wider'.
//This won't work because it is going 'deeper' instead of 'wider'
String id = "1234-4321";
String id2 = "1234-4432";
Query myQuery = myRef.child(id).child(id2);
And then loop through in the listener the same way, but, I would need to create a different DatabaseReference for every chat room, which is horribly inefficient.
It looks like the solution is probably to use filters, but I cannot for the life of me figure out how to utilize them in the existing FirebaseDatabase and DatabaseReference objects. Does anyone have any idea how to make a filter work with regards to the data schema / model I have listed here?
Thanks for the help!
I would try to explain you the basic use of filtering in these examples:
//getting first two chat rooms
Query chatRoomsQuery = databaseReference.limitToLast(2);
//getting last two chat rooms
Query chatRoomsQuery = databaseReference.limitToFirst(2)
//getting all active id
Query chatRoomsQuery = databaseReference.orderByChild("active").equalTo(true);
This is just a basic sample I would encourage you to go through this blog. Which explains advanced queries amazingly.
Alternatively, you can also go through these docs. They are different than what you shared.
Do let me know if this is what you were looking for.