0

I will first say that I am a firmware developer trying to make a web interface for a personal project. My question might be basic as this is my first web interface with a database. I have searched quite a bit on how to achieve what I am trying to do without success, so I suspect I am not approaching this the right way, but here it is:

Basically I have a device pushing data to a firebase realtime database : enter image description here

the push function generates an unique Id for me automatically which is nice...

Now In my flutter interface, I want to display the latest entry on a widget so I am using the onChildAdded functionnality of flutterfire:

ref.onChildAdded.listen((DatabaseEvent event) {
      print(event.snapshot.key);
      print(event.snapshot.value);
});

My first issue is that this function is triggered for all the child at first before waiting for new ones which is unnecessary and could be a problem when I begin to have a lot of data. Is there a way to simply get the latest sample and still get an event when one is added? (I still want to keep the old data to be able to make charts with them)

My second problem is the format of the received data:

{
  -Mx2PCeptLf2REP1YFH0: {
     "picture_url": "", 
     "time_stamp": "2022-02-28 21:56:58.502005", 
     "temperature": 27.71, 
     "relative_humidity": 42.77, 
     "eco2": 691, 
     "tvoc": 198, 
     "luminosity": 4193, 
     "vpd": 1.71
   }
}

before using the put method, I didn't have the automatically generated ID so I was able to cast this as a Map<String, dynamic> and use the data like this in my widget:

Text(snapshot.data!["temperature"].toString())

but now the added nesting with the generated id is giving me a headache as I can't seem to figure out how to simply get the data.

So if anyone could help me to always get the single latest data when subscribing to a collection and how to access that data within my State of my StatefulWidget that would be much appreciated!

ESD
  • 675
  • 2
  • 12
  • 35

1 Answers1

3

My first issue is that this function is triggered for all the child at first before waiting for new ones which is unnecessary and could be a problem when I begin to have a lot of data.

The Firebase Realtime Database synchronizes the state of the path/query that you listen to. So it doesn't just fire an event on onChildAdded for new data, but also for any existing data that you request. There is (intentionally) no way to change that behavior.

So your options here are limited:

  • You can remove the data that your application has processed, so that it doesn't get passed to the clients again. That means you essentially implement a message-passing mechanism on top of Firebase's data-synchronization semantics.

  • You can use a query to only request a certain subset of the child nodes at a path. For example, if you remember the latest key that you've received, you can get data from there on with ref.orderByKey().startAt("-Mx2LastKeyYouAlreadySaw").

Since this comes up regularly, I recommend also checking:

My second problem is the format of the received data:

The screenshot of your database shows two keys, each of which has a single string value. The contents of that value may be JSON, but the way they are stored is just a single string.

If you want to get a single property from the JSON, you either have to:

  • Decode the string back into JSON with jsonDecode.
  • Fix the problem at the source by storing the data as proper JSON, rather than as a string.
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thank you for your help. For "Decode the string back into JSON with jsonDecode.", I guess my issued is more of accessing the json string from the returned object, because I don't necessarily know the key that maps to the json string in advance. So even if I have the Map, I don't know how to simply get the json string when I don't know the id which is the key. It doesn't seem to be addressable like an array with bracket. – ESD Mar 01 '22 at 04:24
  • also if there is no way of getting only the latest data with the event handler, would there be a better way of displaying "the latest data" from a periodic updated data while keeping the old data to be able to use it later? No matter if it is with firestore or realtime database? Sorry again for the basic question, this is all new to me :) – ESD Mar 01 '22 at 04:44
  • `.onChildAdded` should call you with the individual child node, although it's hard to be certain since you didn't show how you initialized `ref` in your code. But if you don't know the key of the child nodes, you can loop over the `children` of the snapshot: https://pub.dev/documentation/firebase_database/latest/firebase_database/DataSnapshot/children.html – Frank van Puffelen Mar 01 '22 at 04:47
  • 1
    I added some more links on the "only new data" question, as this has been covered elsewhere (and probably better) before. :) – Frank van Puffelen Mar 01 '22 at 04:50
  • Getting only the single latest data in subscription form without having to iterate through the existing data or keeping a local cache seems to be a common use case that people are looking for in the realtime database. Are there any plans to implement such a feature in the near future? – ESD Mar 02 '22 at 02:12