I am struggling to write (and also haven't yet figured out how to read) nested maps in firebase from my flutter app. I'm writing an expense tracker where the list of categories is stored within each logbook. I can map, save, and retrieve the primitive fields to and from firebase, where I get lost is trying to write the map of the categories and subcategories to firebase and then how to read them.
Solving for both categories and subcategories is essentially the same so I'll just present one of them. Also, I currently have the category Id as both the key and part of the category class itself, I'll be deleting the Id from the class itself later, as I believe its bad practice, it's just helping me at the moment elsewhere.
I've also been following the BLOC method, so I also have models that convert to entities for dealing with firebase.
This is a category (I've removed irrelevant info such as props and to string):
<pre>
class MyCategory extends Equatable {
final String id;
final String name;
final IconData iconData;
MyCategory({@required this.id, @required this.name, this.iconData});
MyCategoryEntity toEntity() {
return MyCategoryEntity(
id: id,
name: name,
iconCodePoint: iconData.codePoint.toString(),
iconFontFamily: iconData.fontFamily,
);
}
static MyCategory fromEntity(MyCategoryEntity entity) {
return MyCategory(
id: entity.id,
name: entity.name,
iconData: IconData(int.parse(entity.iconCodePoint),
fontFamily: entity.iconFontFamily),
);
}
}
</pre>
The model entity for the category has JsonSerialization and also uses the Icon codepoint/fontFamily as it seems to be more friendly to pass back and forth from firebase than IconData directly.
<pre>
@JsonSerializable()
class MyCategoryEntity extends Equatable {
final String id;
final String name;
final String iconCodePoint;
final String iconFontFamily;
const MyCategoryEntity(
{this.id, this.name, this.iconCodePoint, this.iconFontFamily});
factory MyCategoryEntity.fromJson(Map<String, dynamic> json) =>
_$MyCategoryEntityFromJson(json);
Map<String, dynamic> toJson() => _$MyCategoryEntityToJson(this);
</pre>
I don't think you need to see the Log model as its more the LogEntity that speaks directly to firebase. This is where I'm completely stuck. I've seen a few examples of how to pass a list of objects, but I can't seem to figure out how to pass a map of objects. I'm also not sure how I'd read it back into the LogEntity from firestore (as can be seen in my two TODOs down below).
<pre>
class LogEntity extends Equatable {
final String uid;
final String id;
final String logName;
final String currency;
final bool active;
//String is the category id
final Map<String, MyCategory> categories;
final Map<String, MySubcategory> subcategories;
const LogEntity({this.uid, this.id, this.logName, this.currency, this.categories, this.subcategories, this.active});
static LogEntity fromSnapshot(DocumentSnapshot snap) {
return LogEntity(
uid: snap.data[UID],
id: snap.documentID,
logName: snap.data[LOG_NAME],
currency: snap.data[CURRENCY_NAME],
//TODO de-serialize categories and subcategories
active: snap.data[ACTIVE],
);
}
Map<String, Object> toDocument() {
return {
UID: uid,
LOG_NAME: logName,
CURRENCY_NAME: currency,
//TODO serialize categories and subcategories, this does doesn't work
CATEGORIES: categories.map((key, value) => categories[key].toEntity().toJson()).toString(),
ACTIVE: active,
};
}
}
</pre>
I'm really hoping for some help on this as the only examples I've been able to understand are lists, not maps. Also I want to use a similar method in a few places in this app, so figuring this out is critical.