Nuxt.jsプロジェクトでいろいろな条件を指定してFirestoreからデータを取得する

はじめに

数回に分けてNuxt.jsプロジェクトでデータの永続化を行う方法を解説しています。これらの記事は上から順番に読んでいくことを想定しています。

これらの記事で作成したNuxt.jsプロジェクトは以下のGitHubリポジトリーで公開しています。

GitHub - whitia/nuxt-firebase-sample

前回の記事でFirestoreのデータを取得し表示することができました。しかし、前回は全データをまるっと取得しているだけでした。実際にはいろいろな条件を指定してデータを絞り込むことのほうが多いと思います。

今回は、前回作ったNuxt.jsプロジェクトを使って、Firestoreのデータを条件指定して取得する方法について解説します。

比較条件

前回作ったstore/index.jsfetchUsersメソッドを以下のように変更します。

...

  fetchUsers({ commit }) {
    commit('initUsers')

    return new Promise((resolve, reject) => {
      // 以下の行を変更
      usersRef.where('age', '>=', '25').get()
      .then(res => {
        res.forEach((doc) => {
          commit('addUsers', doc.data())
          resolve(true)
        })
      })
      .catch(error => {
        console.error('An error occurred in fetchUsers(): ', error)
        reject(error)
      })
    })
  }

...

年齢が25歳以上のユーザーに条件を絞ってデータを取得するように変更しました。

25歳未満であるジェーンが除外されました。

以下のように一意なフィールドを条件に指定しても結果は配列で返ってきます。人間が一意なフィールドとして扱っていたとしても、Firestoreにはプライマリキーやユニークキーという概念はありません。

usersRef.where('id', '==', payload.id).get()
.then(snapshot => {
  snapshot.forEach(doc => {
    // 処理
  })
})

今度は以下のように変更してみます。

usersRef.where('age', '>=', '25').order('created_at', 'desc').get()

すると、コンソールに以下のエラーが表示されるます。

Uncaught (in promise) FirebaseError: Invalid query.You have a where filter with an inequality (<, <=, >, or >=) on field 'age' and so you must also use 'age' as your first Query.orderBy(), but your first Query.orderBy() is on field 'created_at' instead.

whereageを指定しているのでorderByでもageを指定せよ、という内容です。うーん、謎仕様...

今度は以下の条件に変更してみます。

usersRef.where('name.first', '!=', 'Jane').get()

実行すると以下のエラーが表示されます。

Uncaught (in promise) FirebaseError: Invalid value "!=" provided to function Query.where() for its second argument. Acceptable values: <, <=, ==, >=, >, array-contains, in, array-contains-any

なんと比較演算子にNOT EQUALは使えないとのことです。NOT EQUALとしたいならwhere("age", "<", "30")where("age", ">", 30)などと指定する必要があります。

しかしこれは数値などの順番があるフィールドでしか使えません。where('name.first', '!=', 'Jane')のように特定の文字列を除外する方法はないのです。特定の文字列を除外したい場合は、いったん除外対象のデータを含んだデータを取得して、そのデータに対して以下のように除外するしかありません。

docs.some((doc, index) => {
  if (doc.name.first === 'Jane') {
    docs.splice(index, 1)
    return true
  }
})

まとめ

いろいろな条件を指定してFirestoreからデータを取得する方法について解説しました。

Firestoreを一般的なデータベースのような感覚で扱うと思わぬ制限事項にはまることになります。この記事で書いてあることはすべてFirebaseのドキュメントに記載されていることですので、まずはそちらに目を通すことをおすすめします。