Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter realtime database onValue parsing

I'm experimenting with NoSQL (firebase realtime database) for the first time and I'm having some issues structuring and parsing data in a Flutter app. At first I had a simple "Person" model with some attributes and all was fine but then I had to introduce an ID as node and nesting the other attributes in order to perform CRUD operations and now I'm not able to parse my "updated" 'Person' model anymore. I don't know if that's ok but, for simplicity (I know it's not a proper ID), I decided that my ID ('personName' attribute) is the name of the person so the current structure on DB is:

realtime db to object

I'm using freezed package and PersonDto looks like this (domains methods omitted):

@freezed
class PersonDto with _$PersonDto  {
  const PersonDto ._();

  const factory PersonDto ({
    required String personName,
    required int age,
    required String genre,
    required double height,
    required String hobby,
    required double weight,
  }) = _PersonDto ;

  factory PersonDto.fromJson(Map<String, dynamic> json) =>
      _$PersonDto FromJson(json);

In the repository there's a method responsible to receive, parse and stream data from firebase. My problem is basically that I'm not able to generate a 'Person' model using the key of the node as an attribute for the 'name'. This is the closest I get :

Stream<Either<PersonFailure, List<Person>>> watchAll() async* {
yield* _firebaseDatabase
    .reference()
    .child('persons')
    .onValue
    .map((event) {
  return right<PersonFailure, List<Person>>(
      (event.snapshot.value as LinkedHashMap).values.map((personMap) {
    final json = Map<String, dynamic>.from(personMap as LinkedHashMap);
//
//this snippet works. I'm able to generate a proper 'Person' model but like this 
//there's no way to retrieve the key from event.snapshot.value
//
    json.addAll({
      'personName': 'NAME OF THE PERSON',
    });
   return PersonDto.fromJson(json).toDomain();     
  }).toList());
}).onErrorReturnWith((e) {
  print('WATCH ERROR ${e.toString()}');
  return left(const PersonFailure.unexpected());
});
}

Should be something like this, which likewise doesn't work, unfortunately:

yield* _firebaseDatabase
    .reference()
    .child('persons')
    .onValue
    .map((event) {
  (event.snapshot as LinkedHashMap).map((key, value) {
    final personName = key;
    final json = value as Map<String,dynamic>;
    json.addAll({'personName':personName});
    //
    //error: The return type 'Person' isn't a 'MapEntry<_, _>', as required by the closure's context.
    //
    return PersonDto.fromJson(json).toDomain();
  });
});
like image 424
Michael m Avatar asked Mar 14 '26 22:03

Michael m


1 Answers

Just need to add a null check. like this;

.....
.onValue
.map((event) {
    List<ListsModel> _offers = <ListsModel>[];
    if(event.snapshot.value != null) {
        final _resultList =
          Map<String, dynamic>.from(e.snapshot.value as LinkedHashMap);
        for (var key in _resultList.keys) {
        Map<dynamic, dynamic> map = Map.from(_resultList[key]);
        ListsModel listsModel = ListsModel.fromMap(map);
        _offers.add(listModel);
    }
}
.....
like image 108
erdemsword Avatar answered Mar 16 '26 14:03

erdemsword



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!