はじめに
先週からwebアプリ作ってまして。
nuxt.js で4月から小学生の息子用に足し算練習webアプリを半日で作成できるか企画
ランキング機能あるとモチベーション上がるだろうと思って firebase でさらっとランキング作ったのですが。
ワイフ「上位陣に動きがなくてつまらない」
ワイ「じゃー、デイリーランキング作るわ」
と言うやり取りがありまして。
そんなこともあろうかとスコア登録日時のタイムスタンプを登録してたのでチョロく出来るかと思って2つ返事をしたら、firestore の制限でハマりましたというお話です。
データ構造
scores [
{
mode: 'ゲームモード', // 複数のゲームモードのスコアを同じテーブルに格納している
name: 'ニックネーム',
score: 得点
createdAt: 登録日時のタイムスタンプ
},
...
]
日指定しないクエリ
const q = db.collection('scores')
.where('mode', '==', this.displayGameMode) // 10秒モード, 30秒モード, 耐久モード
.orderBy('score', this.orderBy) // 'desc' or 'asc'
.limit(100)
複数の項目に対して条件を付ける場合 index を作成する必要があります。
ゲームモードによってスコア昇順 / スコア降順で値を取得したいので2つ index を作成します。
- mode Ascending, score Ascending
- mode Ascending, score Descending
mode は [=] の比較でしか使わないので昇順でも降順でも問題ないです。
index を指定していない状態で query を投げるとブラウザのコンソールに警告が出て、リンクを踏むと上のスクリーンショットのページに遷移し index を作成できるのでここは悩まずイケます。
日指定するクエリ
問題はこちら。
ネットを細切れに検索すると日指定できそうに見え、実際指定できるのですが 他の項目でソートできない という制限があります。
// 動く
const q = db.collection('scores')
.where('mode', '==', this.displayGameMode)
.where('createdAt', '>=', startTime)
.where('createdAt', '<', endTime)
.limit(100)
// 動く
const q = db.collection('scores')
.where('mode', '==', this.displayGameMode)
.orderBy('createdAt', 'desc')
.startAt(startTime) // startAt(>=), startAfter(>)
.endBefore(endTime) // endAt(<), endBefore(<)
// 動かない
const q = db.collection('scores')
.where('mode', '==', this.displayGameMode)
.where('createdAt', '>=', startTime)
.where('createdAt', '<', endTime)
.orderBy('score', this.orderBy) // ★範囲で取得する値と異なる項目でソートできない
.limit(100)
回避
日付に貼り付けて登録も取得も行う様にして、= で比較出来るようにしました。
// 動く
const q = db.collection('scores')
.where('mode', '==', this.displayGameMode)
.where('createdAt', '=', startTime)
.orderBy('score', this.orderBy)
.limit(100)
おわりに
開発進んでからこういうのに気づくと致命傷だったりするのでお気をつけください。