PROGBLOG Developers Blog

空想家 Developers Blog

稼ぐ力? とにかくスキルが欲しい。

Firebase のRealtime Database で取得した情報が重複しないようにする

はじめに

FirebaseRealtime 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 に保存しておく必要がある。