※タイトルにWHERE IN 的なことをしたいと書いていますが実際にはWHERE INとはほど遠く複数クエリをFirebaseに投げています
※そもそもFirebase Realtime Database自体が初心者なため、データ構造から自信がありません。 また、Promiseも理解しきれておりません。 もっと良い方法がありましたらご教示頂けると幸いです。
前提
React+FirebaseでSPAを開発
困ったこと
- あるユーザに紐付くデータ(モデル)が複数個ある
- 紐付けは以下のようにモデルのIDで持っている
"users": {
"ID-USER-abcde": {
"username": "tanaka",
"data": {
"ID-DATA-ABCDE": true,
"ID-DATA-FGHIJ": true
}
},
..snip..
},
"data": {
"ID-DATA-ABCDE": {
"num": 3
},
"ID-DATA-FGHIJ": {
"num": 5
},
"ID-DATA-KLMNO": {
"num": 8
},
..snip..
}
- やりたいことはSQLでいう
SELECT * WHERE IN ("ID-DATA-ABCDE", "ID-DATA-FGHIJ");
- しかしFirebase Realtime Databaseにそのようにクエリする方法はない
方針
- 改めてFirebaseに用意されている関数を確認してみる。
orderByChild()、orderByKey()、orderByValue()
/limitToFirst()、limitToLast()、startAt()、endAt()、equalTo()
=> やりたいことはできなさそう - dataを全部持ってきてクライアントでフィルタする => 流石にネットワーク効率が非効率的な気がする
- userに対するdataはそこまで多くなる予定はないので、 一つ一つ取得する
やったこと
Reactで開発しており、全てのデータを取得してからstateを更新したかった。 => Promise.all
を使った
firebase
.db
.ref("User's data")
.once('value')
.then(snapshot => {
const dataObject = snapshot.val()
// ["ID-DATA-ABCDE", "ID-DATA-FGHIJ"] にする
const dataIds = Object.keys(dataObject)
const promises = dataIds.map(v =>
firebase
.db
.ref("data")
.once('value')
)
// 全てのデータ取得が完了してからstateを更新する
Promise.all(promises).then(v => {
// [{"num": 3}, {"num": 5}]
const data = v.map(snapshot => snapshot.val())
this.setState({
data
loading: false
})
})
})
これでやりたかったことは実現できました。
const promises
もPromise.all
も.then
の外にだせる気もするんだけどjavascript力が弱い...