Open1

Firebaseの逆引き大全

shohei@株式会社Nevershohei@株式会社Never

Firestoreで集計機能を作りたい(Firestore Aggregation)

集計クエリを使用してデータを集計する

  • count: 特定のクエリに一致するドキュメント数
  • sum: 特定のクエリに一致する数値の合計値
  • average: 特定のクエリに一致する数値の平均値

サンプルコード

1回のクエリでcount, sum, averageの値を取得できる
クエリ内の複数の集計を計算
typedef Result = ({int count, double sum, double average});


class FetchAggregation extends _$FetchAggregation {
  
  Future<Result> build() async {
    final snap = await FirebaseFirestore.instance
        .collection('aggregation')
        .aggregate(count(), sum('value'), average('value'))
        .get();

    final result = (
      count: snap.count ?? 0,
      sum: snap.getSum('value') ?? 0.0,
      average: snap.getAverage('value') ?? 0.0,
    );
    return result;
  }
}

追加で取得したいフィールドがあれば、aggregate内に指定する(最大30個まで)。

その他のクエリ

Where

where

class FetchAggregation extends _$FetchAggregation {
  
  Future<Result> build() async {
    final snap = await FirebaseFirestore.instance
        .collection('aggregation')
        .where('value', isEqualTo: 3)
        .aggregate(count(), sum('value'), average('value'))
        .get();

    return (
      count: snap.count ?? 0,
      sum: snap.getSum('value') ?? 0.0,
      average: snap.getAverage('value') ?? 0.0,
    );
  }
}
where + 複数フィールド

class FetchAggregation extends _$FetchAggregation {
  
  Future<Result> build() async {
    final snap = await FirebaseFirestore.instance
        .collection('aggregation')
        .where('status', isEqualTo: 0)
        .where('value', isEqualTo: 7)
        .aggregate(count(), sum('value'), average('value'))
        .get();

    return (
      count: snap.count ?? 0,
      sum: snap.getSum('value') ?? 0.0,
      average: snap.getAverage('value') ?? 0.0,
    );
  }
}
where + Filter.or

class FetchAggregation extends _$FetchAggregation {
  
  Future<Result> build() async {
    final snap = await FirebaseFirestore.instance
        .collection('aggregation')
        .where(
          Filter.or(
            Filter('value', isEqualTo: 5),
            Filter('value', isEqualTo: 7),
          ),
        )
        .aggregate(count(), sum('value'), average('value'))
        .get();

    return (
      count: snap.count ?? 0,
      sum: snap.getSum('value') ?? 0.0,
      average: snap.getAverage('value') ?? 0.0,
    );
  }
}
where + Filter.or + 複数フィールド

class FetchAggregation extends _$FetchAggregation {
  
  Future<Result> build() async {
    final snap = await FirebaseFirestore.instance
        .collection('aggregation')
        .where(
          Filter.or(
            Filter('value', isEqualTo: 9),
            Filter('status', isEqualTo: 1),
          ),
        )
        .aggregate(count(), sum('value'), average('value'))
        .get();

    return (
      count: snap.count ?? 0,
      sum: snap.getSum('value') ?? 0.0,
      average: snap.getAverage('value') ?? 0.0,
    );
  }
}

クエリカーソル

orderBy + startAt

class FetchAggregation extends _$FetchAggregation {
  
  Future<Result> build() async {
    final snap = await FirebaseFirestore.instance
        .collection('aggregation')
        .orderBy('value')
        .startAt([9])
        .aggregate(count(), sum('value'), average('value'))
        .get();

    return (
      count: snap.count ?? 0,
      sum: snap.getSum('value') ?? 0.0,
      average: snap.getAverage('value') ?? 0.0,
    );
  }
}

料金体系

インデックスエントリ0〜1000個に対して1カウント、1回のドキュメントの読み取りとして課金。

料金体系