Firebase のRealtime Database で取得した情報が重複しないようにする
はじめに
Firebase
の Realtime Database
から情報を取得し、 Nuxt.js の v-for
で表示させた。
初回はうまく読み込みのだが、新しくデータを追加し、.on
メソッドで呼び出したとき、今までのデータが1から呼び出され、過去のデータが2重に書き込まれた。
わかりにくいので、図のようにしてみる。
〇〇〇〇〇 ××××××××× △△△△△
に☆☆☆☆☆
を追加すると
〇〇〇〇〇 ××××××××× △△△△△ 〇〇〇〇〇 ××××××××× △△△△△ ☆☆☆☆☆
となる。
これを解決したい。
こうなったコード
created: function() { firebase.database().ref(this.user.uid).on("value", (snapshot) =>{ snapshot.forEach((childSnapshot) =>{ let childData = childSnapshot.val(); console.log(childData) this.details.push(childData); }) }) },
.on()
メソッドが発火されるたびに、実行される。
またvalue
は下記の通り。
イベントの種類
value
を使用しました。この種類のイベントは、データがほんの 1 か所変更されただけでも、Firebase
データベース参照のコンテンツ全体を読み取ります。
つまり、何かを追加すると、Firebase
データベース参照のコンテンツ全体を読み取り、表示される。
結果、前述の図のような事象が発生する。
コードと解決方法
created: function() { // firebaseからデータを取得する(初回) firebase.database().ref(this.user.uid).once("child_added", (snapshot) =>{ snapshot.forEach((childSnapshot) =>{ let childData = childSnapshot.val(); console.log(childData) this.details.push(childData); }) }) // firebaseからデータを取得する(初回以降) firebase.database().ref(this.user.uid).orderByValue().startAt(this.chekTime).on("child_added", (snapshot) =>{ let childData = snapshot.val(); this.details.push(childData); }) },
解説
// firebaseからデータを取得する(初回) firebase.database().ref(this.user.uid).once("value", (snapshot) =>{ snapshot.forEach((childSnapshot) =>{ let childData = childSnapshot.val(); console.log(childData) this.details.push(childData); }) })
まず1つ目の塊はほとんど前回のコードと変更なし、唯一の変更点は.on()
を.once()
に。
ただこれが非常に重要で、.once()
は下記の通り。
once()
メソッドを使用して、このシナリオを簡素化できます。このメソッドは 1 回トリガーされ、その後再びトリガーされることはありません。
つまり、最初の読み込み時のみの記述になる。
次の塊は2回目以降の処理になる。
// firebaseからデータを取得する(初回以降) firebase.database().ref(this.user.uid).orderByValue().startAt(this.checkTime).on("child_added", (snapshot) =>{ let childData = snapshot.val(); this.details.push(childData); })
こちらは.on
で都度都度データを取得する。
ただ前回のコードと違うのは、新規で追加されたデータだけを取得することができる点。
それを可能にしているのが、下記のコード。
.orderByValue().startAt(this.checkTime)
まず.orderByValue()
は下記の通り。
orderByValue()
を使用すると、子がその値で並べ替えられます。並べ替えの条件は、指定した子キーの値の代わりにノードの値が使用されるという点を除いて、orderByChild()
の場合と同じです。
そして.startAt()
は下記の通り。
startAt()
、endAt()
、equalTo()
を使用すると、クエリに対し任意の始点と終点を選択できます。
この絞り込みにより初期化時(this.checkTime
)*1以降に追加された要素に対してトリガーをするよう対象を絞り込むことができた。
*1:checkTime は投稿時にFirebase に保存しておく必要がある。