ページネーションを実装する時など、前回のデータの次のデータからn件取得したいというニーズがあるかと思います。
twitterのようにページの下端までスクロールすると追加で10件読み込むというような実装をしようと思い下記のように実装しました。
final CollectionReference<Map<String, dynamic>> _collection = FirebaseFirestore.instance.collection('tweet');
Query<PushNotificationMessage> query = _collection
.orderBy('createdAt',descending: true)
.startAfter([lastTweet.createdAt])
.limit(10)
.get()
startAfterに渡したタイムスタンプ以降のデータが10件取得されます。
このコードで取得できたデータの最後のデータをまたlastTweetとし、次回実行時に再びこの関数に渡してあげることで11件目からさらに10件のデータを取得することができます。
ですが10件目と11件目が全く同じ時間のタイムスタンプを持っていた場合、次回の実行時に11件目のデータが取得されず12件目から10件のデータが取得されてしまいます。
そこでstartAfterにidを渡してそのid以降のデータを10件取得するというような実装にしようと以下のように修正しましたが、うまく機能しませんでした。
Query<PushNotificationMessage> query = _collection
.orderBy('createdAt',descending: true)
.startAfter([lastTweet.id])
.limit(10)
.get()
startAfterが無視され、先頭から10件のデータが取得されてしまいます。
startAfterに渡す値はorderByで指定したフィールドの順番通りに渡さなければならないようです。
Query<PushNotificationMessage> query = _collection
.orderBy('createdAt',descending: true)
.orderBy('id')
//createdAt, idの順にリストで渡す
.startAfter([lastTweet.createdAt, lastTweet.id])
.limit(10)
.get()
意図するように動きました。
初回の呼び出し時にはlastTweetが手元にないので.startAfterメソッドは必要ありません。
Query<PushNotificationMessage> query = _collection
.orderBy('createdAt',descending: true)
.orderBy('id')
.limit(10)
.get()
メソッドを後から追加する場合、変数に再代入することを忘れないようにしましょう。
if (lastTweet != null) {
query = query.startAfter([lastTweet.createdAt, lastTweet.id]);
}