Posted at

Javascript + Firebase Realtime DatabaseでSQLのWHERE IN 的なことをしたい

※タイトルに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 promisesPromise.all.thenの外にだせる気もするんだけどjavascript力が弱い...