FlutterでFirestoreのReferenceを取得する
FirestoreのReference指定している値も合わせて取得する時にハマったので、実装方法のメモ.
前提
シリアライズ処理は, json_serializable
を使用する.
Firestore側の構造は以下.
items
とusers
のコレクションを持っており, items.user
にusers
のリファレンスが貼ってある.
items
の取得時にのuser
の値も合わせて取得する.
Modelの処理
Modelには処理は追加せずに, デフォルト.
NOTE: freezed
が入っているが, 今回の処理には関係ない
// item.dart import 'package:flutter/foundation.dart'; import 'package:flutter_mvvm/data/model/user.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'item.freezed.dart'; part 'item.g.dart'; @freezed abstract class Item with _$Item { const factory Item({ @required String name, @required User user, }) = _Item; factory Item.fromJson(Map<String, dynamic> json) => _$ItemFromJson(json); }
// user.dart import 'package:flutter/foundation.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'user.freezed.dart'; part 'user.g.dart'; @freezed abstract class User with _$User { const factory User({ @required String name, }) = _User; factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json); }
所得処理
今回はFirestoreのワンショットの取得方法での実装.
全体の処理は以下になる.
// item_repository.dart import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter_mvvm/data/model/item.dart'; class ItemRepository { @override Future<List<Item>> getItems() async { return Firestore.instance .collection('items') .getDocuments() .then((result) { // 各userの取得部分Future関数でまとめる. return Future.wait(result.documents.map((it) async { // userドキュメントを再度取得する. var user = await it.data["user"].get(); // 取得したuserを, itemをコピーした値に入れる. // // memo // it.data["user"] = user.data は x // it.dataはkey,valueの型が固定のlinkdedHashMapになっており, // 別の型で値を上書きできない. // Map.fromも同じなので, Map.ofを使用. var clone = Map.of(it.data)..["user"] = user.data; // マッピング処理をして返す. return Item.fromJson(clone); })); }); } }
まとめ
もっと良い方法はありそうだが, 自分では一応これで進める.
@JsonKey
とかを使って, モデル側にガリガリマッピング処理を書いてもいいけど, 以下の理由でデータ取得時に完結させている.
- Firestoreをなるべく外に出したくなかった.
- 全体的な書き換えがあってもRepository層の書き換えでいける.
- モデルクラスはなるべく簡潔にしたかった.
実際の実装ではUseCase層とか用意したほうがいいかも.
デメリットとしては, Reference
が増えると, Repository層は地獄になる.
他にいい方法が教えてほしいです...orz
おわり.