'How to populate firebase reference type in flutter
This is how my firebase firestore data look like
You can see that I have the person
data field which is a reference type.
And this is how I retrieve data from my flutter dart,
Query<Map<String, dynamic>> persons = FirebaseFirestore.instance
.collection('fl_content')
.where('_fl_meta_.schema', isEqualTo: 'talks');
This query can get only the parent level of data, but not person
's detail values.
In person
, I have fields like Name, Age, PhotoUrl.
How can I get and populate those values together?
The result I want is
Result
------
id: "N48xxxxx"
saidWhat: 'HiThere'
Name: 'PersonName'
Age: 30
PhotoUrl: 'url'
I used Flamelink for backend firebase cms.
Solution 1:[1]
A bit beside the point of your question, but I would recommend using sub collections (https://firebase.google.com/docs/firestore/data-model) for the person's data, as you are going to make your life harder by mixing the document "types" in the fl_content collection. You'll also want to be careful not to use the reference as a foreign key
That being said, see below a potential solution to answer your question.
If your goal is only to get read data, you can just map trigger the call to Firestone from the reference:
List<DocumentSnapshot> persons = await FirebaseFirestore.instance
.collection('fl_content')
.where('_fl_meta_.schema', isEqualTo: 'talks')
.get();
persons = await Future.wait(persons.map((_) => _.data().person.get()));
(didn't test, but the idea is there). This one makes sense as it is only fetching the persons you need, BUT it is expensive in terms of http calls and Firestone roundtrips.
An other option, would be to fetch all talks, and all persons, and map them together. You might be fetching unused data which is a bit of a bad practice, but it will be less expensive than the first option (I assumed that your schema
would be persons
:
List<DocumentSnapshot> talks = await FirebaseFirestore.instance
.collection('fl_content')
.where('_fl_meta_.schema', isEqualTo: 'talks')
.get();
List<DocumentSnapshot> persons = await FirebaseFirestore.instance
.collection('fl_content')
.where('_fl_meta_.schema', isEqualTo: 'persons')
.get();
Map<String, dynamic> mappedTalks = talks.map((_) => ({..._.data(), person: persons.firstWhere((__) => __.id == _.person.id, orElse: () => null)}));
(also didn't test, but the idea is also here ;) )
Solution 2:[2]
In NoSQL databases like Firebase it is common standard to create collections holding redundant data, each of them tailored to (one or more) specific READs.
One does not combine several READs; instead on creates a collection which allows to get all the relevant data with one single READ.
The reason for this is speed of access over the Internet. This speed is traded for the increasing amount of storage needed for holding redundant data.
The redundant data is usually kept in sync with the help of Firebase Functions, which listen to changes in collection A and subsequently update elements in collection B.
Example
Say, one has these collections:
- User
- Messages
To get the messages of a user in a performant way, one creates a tailored redundant collection which combines the other two (and leaving out data that is not necessary for the specific READ / Use Case like date of birth or address):
- UserMesssages
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Guillaume Ferron |
Solution 2 | Dabbel |