Open8

毎回忘れるflutter/firestoreのTIPS

草野洋平草野洋平

firestoreでの時刻のクエリ


QuerySnapshot ss = collectionRef.orderBy().startAt().endAt();

草野洋平草野洋平

モデルクラスのサンプルコード(Enum,fromFirestore, toFirestore)

reservation.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'reservation.freezed.dart';
part 'reservation.g.dart';

enum BathName {
  NIJI("虹"),
  SORA("空"),
  KUMO("雲");

  const BathName(this.displayName);
  final String displayName;
}


class Reservation with _$Reservation {
  const Reservation._();
  factory Reservation({
    required String uid,
    required DateTime date,
    required DateTime fromTime,
    required DateTime endTime,
    required BathName bathName,
    String? guestName,
    String? phoneNumber,
    (false) isOccupied,
  }) = _Reservation;

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

  factory Reservation.fromFireStore(
    DocumentSnapshot<Map<String, dynamic>> snapshot,
    SnapshotOptions? options,
  ) {
    DateTime toDateTime(Timestamp value) {
      return value.toDate();
    }

    final data = snapshot.data();
    return Reservation(
        uid: data?["uid"],
        date: toDateTime(data?["date"] as Timestamp),
        fromTime: toDateTime(data?["fromTime"] as Timestamp),
        endTime: toDateTime(data?["endTime"] as Timestamp),
        bathName:
            BathName.values.byName(data?["bathName"]), // data?["bathName"],
        guestName: data?["guestName"],
        phoneNumber: data?["phoneNumber"],
        isOccupied: data?["isOccupied"]);
  }
  Map<String, dynamic> toFireStore() {
    return {
      "uid": uid,
      "date": date,
      "fromTime": fromTime,
      "endTime": endTime,
      "bathName": bathName.name,
      "guestName": guestName,
      "phoneNumber": phoneNumber,
      "isOccupied": isOccupied
    };
  }
}

草野洋平草野洋平

こちらを扱うcollectionreferenceのサンプルコード

sample.dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../models/reservation.dart';
import 'user_provider.dart';

part 'business_days_provider.g.dart';

//まずはUserを使ってCollectionReference作る
//withConverterメソッド使ってタイプセーフに受け取る。
final reservationsRef = Provider<CollectionReference<Reservation>>(((ref) {
  final db = FirebaseFirestore.instance;

  final _user = ref.watch(currentUser);
  final reservations = db
      .collection("user/${_user.uid}/reservations")
      .withConverter(
          fromFirestore: Reservation.fromFireStore,
          toFirestore: ((Reservation reservation, options) =>
              reservation.toFireStore()));
  return reservations;
}), dependencies: [currentUser, targetDayProvider]);

//クエリを使う。この場合はtimestampでクエリを作ってそれをStreamProviderを使って描画している。

final targetReservationsProvider =
    StreamProvider.autoDispose<List<Reservation>>(((ref) async* {
  final _targetDate = ref.watch(targetDayProvider);
  final startAt =
      DateTime(_targetDate.year, _targetDate.month, _targetDate.day, 0, 0);
  final endAt =
      DateTime(_targetDate.year, _targetDate.month, _targetDate.day, 23, 59);
  print('target date : $_targetDate and startAt $startAt , endAt $endAt');
  final _reservationsRef = ref.watch(reservationsRef);
  final ss = await _reservationsRef
      .orderBy("fromTime", descending: false)
      .startAt([Timestamp.fromDate(startAt)]).endAt(
          [Timestamp.fromDate(endAt)]).snapshots();
  await for (final snapshot in ss) {
    final data = snapshot.docs.map((s) => s.data()).toList();
    print("data : $data");
    yield data;
  }
}), dependencies: [currentUser, targetDayProvider, reservationsRef]);

//targetDayprovider , code generationを使ってみたかっただけ。

class TargetDay extends _$TargetDay {
  
  DateTime build() {
    return DateTime.now();
  }

  void setDate({required DateTime date}) {
    state = date;
  }
}

//CRUD用のクラスを作る。描画と分けることで簡素に作れる。
final reservationHandlerProvider = Provider(
    (ref) => ReservationHandler(ref: ref),
    dependencies: [currentUser, reservationsRef]);

class ReservationHandler {
  ReservationHandler({required this.ref});
  Ref ref;
  void update(Reservation reservation) {
    final _reservationsRef = ref.watch(reservationsRef);

    final docRef = _reservationsRef.doc(reservation.uid);
    docRef.set(reservation);
  }

  void delete(Reservation reservation) {
    final _reservationsRef = ref.watch(reservationsRef);
    final docRef = _reservationsRef.doc(reservation.uid);
    docRef.delete();
  }
}


草野洋平草野洋平

code generation使ってみたかったから使ってみたけど、今のところ使いづらいと思った。

草野洋平草野洋平

whereorderByはどうも一緒には使えない?エラーが出た。もしかしたら自分のクエリがおかしいせいかもしれない。

草野洋平草野洋平

FirebaseQueryBuilderを使って場当たり的にUIを作っていったほうが使いやすい。
ProviderもQueryか、DocRefのプロバイダのみで良い。

DocRefの値を使うときはFutureProviderを使うと楽に取得できる。