📥

firestoreから取得したデータをモデルに変換する

2024/05/22に公開

やりたいこと

firestoreから取得したデータをfreezedで作成したデータモデルに変換する。

対応方法

firestoreに用意されているwithConverter()というメソッドでうまいこと変換できました。

withConverter() の使い方

以下の様にfirestoreのqueryに繋げて呼び出します。

FirebaseFirestore.instance.collection("categories").withConverter(
	fromFirestore: Category.fromFirestore,
	toFirestore: (Category model, _) => model.toFirestore(),
);

引数で、データモデルへ相互変換する関数を渡します。

  • fromFirestore: DocumentSnapshot<Map<String, dynamic>> からデータモデルへの変換
  • toFirestore: データモデルからMap<String, dynamic> への変換

変換関数の定義

変換関数はwithConverter() 内でベタ書しても動作しますが、データモデルの定義内で実装することで、コードの凝集性を高められます。

以下の通り、データモデルを生成するファクトリ(fromFirestore)とMap型へ変換するメソッド(toFirestore)を追加しました。
単純にデータモデルに変換すると、ドキュメントのIDが参照できないので、fromFirestore内で付与しています。


class Category with _$Category {
  const Category._(); // ←Point!!

  const factory Category({
    String? id,
    required String name,
  }) = _Category;

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

	// ↓ここから下を追加
  factory Category.fromFirestore(
    DocumentSnapshot<Map<String, dynamic>> snapshot,
    _,
  ) {
    final data = snapshot.data();
    return Category(
      id: snapshot.id,
      name: data?['name'],
    );
  }

  Map<String, dynamic> toFirestore() {
    return {
      "name": name,
    };
  }
}

補足

上記ではモデルにIDの付与を行いましたが、もしデータの中身に対して特別な処理が要らなければ、freezedで自動生成されるfromJson/toJsonをwithConverterから呼び出せば、データモデルへの修正なしで実現できます。

FirebaseFirestore.instance.collection("categories").withConverter(
  fromFirestore: (DocumentSnapshot<Map<String, dynamic>> snapshot, _) =>
              Category.fromJson(snapshot.data()!),
	toFirestore: (Category model, _) => model.toJson(),
);

参考情報

https://firebase.google.com/docs/firestore/query-data/get-data?hl=ja#custom_objects
https://zenn.dev/joo_hashi/articles/17f9fad30426dd
https://hamburger.hatenablog.jp/entry/2020/08/31/FlutterのFreezedで生成するClassにメソッドを追加する
https://pub.dev/packages/freezed#adding-getters-and-methods-to-our-models

Discussion