Lazy loading Firestore foreign object in Flutter/dart

Viewed 97

A lot of my search regarding this topic seems to refer to pagination. Maybe I'm asking the wrong question. If so please help to edit the question so that it makes sense.

What I mean by lazy loading foreign object is the act of loading only the string id or reference path and converting it to a dart object when needed. I'm trying to replicate the implementation of Ormlite's Foreign Object Fields.

This just seems like a no brainer for complex relationships between collections, because I wouldn't want to read the referenced object if I don't have to. And yet I can't seem to find any way to do this with Firebase easily.

Let's take the following simple data model example:

class Parent {
  String id;
  Child child;
}

class Child {
  String id;
  String description = 'child of parent';
  ParentCousin parentCousin;
}

class ParentCousin {
  String id;
  ChildCousin child;
}

class ChildCousin {
  String id;
  String description = 'child of ParentCousin';
}

This is just a simple model to demonstrate the necessity for lazy loading objects. You can imagine, if the relationship becomes a bit more complex, loading all the objects upfront will be taxing and unnecessary. Is there a best practice to architect a data model that lazily fetch the referenced object when it is called? What I've thought about so far:

1. Wrap each referenced data model in a Map<String, Object> objRef

This way the fetching operation of the parent object will store the id as the key with an initial null object. The object will only be created when the objRef['id'] is referenced.

2. Wrap each referenced data model in a specialised Reference class

Similar to the first approach, the reference class will hold an id and the object. The advantage with this approach would mean that the class can have specialised methods defined by the parent on how to fetch its child. See example:

class Reference<T> {
  String id;
  T _object; 
  T Function() fetch;

  // Todo Constructor

  T get object => fetch;
}

3. Create placeholder child objects

In this approach a child object can have the following state:

  • Unfetched - the id is filled but other fields have not been populated (not loaded)
  • Fetched - the id is filled and other fields are populated (loaded)
  • Empty - the id is an empty string (no need to load, there is no child)

I can already feel that this is going to be a lot of boiler plate having to manage the state of the models, not to mention I'm introducing logic into the model itself, which breaks abstraction rules such as MVC or Bloc pattern.

Any existing solution out there or suggestions on best practice?

0 Answers
Related