PhpStormと僕

日々周りを巻き込むことをモットーに。気まぐれでJetBrains製のIDEネタとか書いてます。

FirestoreのSubCollectionに対してQueryが使えない問題にどう立ち向かうか

Firestore、便利ですよねぇ。 ただ、2018/03執筆時点ではまだβなので荒削りだったり要件満たしにくい部分でつらいなぁっていう部分はいくつかあります。

その1つが表題の件の「SubCollectionにQueryが使えない」問題。 どういうことかというと、例えば「CDごとに曲名とその曲番号(連番)を保持する」構造を例に考えてみます。

- albums [collection]
    - title
    - musics [collection]
        - title
        - songNumber

Firestoreでどう表現するかというと、disksっていうCollectionを作って、その中にSubCollectionとしてmusicsを持つ形が一番シンプルに見えます。

f:id:rinrin900:20180309180400p:plain

こんなイメージ。ただ、この構造の場合は表題の制限があり、musics内のデータを直に参照したいケース、 具体的には「ユーザ属性は曲のタイトルを持っているが、その曲がどのアルバムに属しているか分からない(紐付けることができない)」時に、sounds内のデータを特定することができません。 この件についてStackOverFlowGoogleエンジニアが「Collection group queryという機能で提供する予定だが、提供はすぐではない」という回答をしています。

ObjectやArrayとして下位データを持つ方法もなくはないですが、そもそものSubCollectionのメリットを活かせないのではここでは考慮から外しつつ、 Collectionであることメリットを活かし現時点で解決できるパターンをいくつか見ていきます。

親CollectionにSubCollectionのキー一覧を持つ方法

f:id:rinrin900:20180309181719p:plain

親のCollection側に、soundsのキー一覧を持つのが一案としてあります。

soundKeys: [
    "1. 主よ,人の望みの喜びよ(In 4 Mix)"
    "2. 眠れる森~Sleeping Forest",
    "3. Mouring The Passing Time"
]

キー一覧を持つ際、上記のようにFirestore内のデータとして配列で持ちたくなります。 が、Queryでwhere in句のように配列を対象に検索することができないので、以下のようなObject形式で持つ必要があります。

soundKeys: {
    "1. 主よ,人の望みの喜びよ(In 4 Mix)": true,
    "2. 眠れる森~Sleeping Forest": true,
    "3. Mouring The Passing Time": true
}

sound側のkeyを持っている状態からこのalbums -> soundsのdocを取得する場合には

const userPlayingTitle = '2. 眠れる森~Sleeping Forest'
const querySnapshot = await db.collection('albums')
    .where(`albums.${userPlayingTitle}`, '==', true).get()
...

というような形でquerySnapshotを持ってくることができるようになりました。