masalibの日記

システム開発、運用と猫の写真ブログです

React Firebase入門 Firestoreのデータ取得の補足

masalib.hatenablog.com の補足記事になります

データ取得を色々試してみた結果になります。

whereとorderbyの関係について

RDBのみたいに簡単にwhereを追加できるのかと思いきや

const colRef = db.collection("members")
   .where("docId", "!=", "0w9ZviC6D60yR6QVcEjv")
   .orderBy('createdAt', 'desc')
   .limit(10);
// =>FirebaseError: Invalid query. You have a where filter with an inequality (<, <=, >, or >=) on field 'docId' and so you must also use 'docId' as your first argument to Query.orderBy(), but your first orderBy() is on field 'createdAt' instead

Whereに使用したカラムをorderbyの第1カラムに設定しないといけないもよう・・・

・ω・「まじ使えない

公式のドキュメントにも記載されています

Cloud Firestore で単純なクエリと複合クエリを実行する  |  Firebase

whereとorderbyのカラムが違う場合

もしwhereとorderbyが違う場合はsort部分は自前で作る必要があります。

const collectionRef = db.collection("members")
var query = await collectionRef.where("docId", "!=", "0w9ZviC6D60yR6QVcEjv").get();
const result = query.docs.map(doc => doc.data());

result.sort(function(a,b){
    if(a.createdAt>b.createdAt) return -1;
    if(a.createdAt < b.createdAt) return 1;
    return 0;
});
console.log(result)

(^o^)「まじ使えない

データが少ない場合はいいけどデータが多くてページネーションが必要になると

\(^o^)/オワタ

単一のカラムに複数の条件をいれる場合

const collectionRef = db.collection("members")
var query = await collectionRef.where("docId", "<=", "0w9ZviC6D60yR6QVcEjv").where("docId", ">=", "0w9ZviC6D60yR6QVcEjv").get();
const result = query.docs.map(doc => doc.data());
console.log(result)

これは問題なく動きました

whereが複数になった場合

単純に「=」のAND処理なら問題なく動きます

const collectionRef = db.collection("members")
var query = await collectionRef.where("email", "==", "masalib@gmail.com").where("displayName", "==", "masaddd").get();
const result = query.docs.map(doc => doc.data());
console.log(result)

array-contains 句(<、<=、>、>=、!=)をいれると

const collectionRef = db.collection("members")
var query = await collectionRef.where("email", "==", "masalib@gmail.com").where("displayName", ">=", "masaddd").get();
const result = query.docs.map(doc => doc.data());
console.log(result)
// FirebaseError: The query requires an index. You can create it here
// https://console.firebase.google.com/u/0/project/learn-firebase-masalib/firestore/indexes?create_composite=ClZwcm9qZWN0cy9sZWFybi1maXJlYmFzZS1tYXNhbGliL2RhdGFiYXNlcy8oZGVmYXVsdCkvY29sbGVjdGlvbkdyb3Vwcy9tZW1iZXJzL2luZGV4ZXMvXxABGgkKBWVtYWlsEAEaDwoLZGlzcGxheU5hbWUQARoMCghfX25hbWVfXxAB

複合インデックスを作らないと動かない。 リンクが表示されているのでクリックすると

f:id:masalib:20201205123418p:plain

インデックス作成画面が表示される

Cloud Firestore でのインデックス管理  |  Firebase

つくれば動くけど・・・indexは10件ぐらいしかないデータなのに3分もかかりました。

大量のデータならわかるだけどちょっとしたデータならいらんやろ

(^o^)「めんどくさい

レコード件数のみ取得

2020/12/05の時点ではできない。もし1万件のレコードがある場合は1万件のレコードを取得しないと判別できない。functionsでレコード件数をとれるらしいがまだ検証していない

https://qiita.com/atomyah/items/f94b279febccca030896

(^o^)「え・・ないの??マジで使えない

offset(失敗パターン)

公式に書いてあったからやってみたが取れなかった
https://googleapis.dev/nodejs/firestore/latest/Query.html#offset

webのモジュールにはないのかな・・・・

const query = await db.collection("members")
        .orderBy('createdAt', 'desc')
        .limit(2)
        .offset(3)
        .get();
const result = query.docs.map(doc => doc.data());
console.log(result);
// => TypeError: _firebase__WEBPACK_IMPORTED_MODULE_2__.db.collection(...).orderBy(...).limit(...).offset is not a function

次ページ取得処理

startAfterというメソッドがある。そちらを使えば簡単にとれる 「XXXXcurrentLastRecordXXXX」は現在、表示しているレコードの最後のレコードになる。 データを取得する度にセットしなければならない。

const query = await db.collection("members")
      .orderBy('docId', 'desc')
      .limit(3)
      .startAfter('XXXXcurrentLastRecordXXXX')
      .get();
 const result = query.docs.map(doc => doc.data());
 console.log(result);

前ページ取得処理(失敗パターン)

endAtは後ろからとっていく事をしてくれないので使えなかったwww

const query = await db.collection("members")
        .orderBy('docId', 'desc')
        .limit(2)
        .endAt(XXXXcurrentFirstRecordXXXX)
        .get();
const result = query.docs.map(doc => doc.data());
console.log(result);
//例
// XXXXcurrentFirstRecordXXXXは5とする
// 1,2,3,4,5,6,7,8というデータがある    
// 現在表示しているのは5,6だった場合に
// .endAt(5)にすると自分のイメージだと 3,4のデータ取得されると思っていたが
// 実際には1,2のデータ取得された。使えない

前ページ取得処理(成功パターン)

const query = await db.collection("members")
        .orderBy('docId' )
        .limit(2)
        .startAfter(XXXXcurrentFirstRecordXXXX)
        .get();
console.log(query.size);
const result = query.docs.map(doc => doc.data());
//sort処理
result.sort(function(a,b){
    if(a.docId>b.docId) return -1;
    if(a.docId < b.docId) return 1;
    return 0;
});
console.log(result);

.orderBy('docId' )のソートの条件が変わっている事が大事です 自分でソートを逆転してそのデータをローカルにもってきてから更に逆転する事でうまいこと表示できる

例 1,2,3,4,5,6,7,8,9,10,11のデータがある時に、 currentのデータの範囲が4,5,6だった。
XXXXcurrentFirstRecordXXXXは4になる。 4のレコードを基軸にデータを取得する。取得したデータは3,2,1になる。そのデータを逆転ソートをすることで 1,2,3になって正しく表示する事ができる

like文

Likeは標準の機能にないです。以下の記事を参考にしました

qiita.com

const keyword = "masa";
const query = await db.collection("members").orderBy("displayName").startAt(keyword).endAt(keyword + '\uf8ff').get();
const result = query.docs.map(doc => doc.data());
console.log(result);

(^o^)「普通はあるやろ!!

どうしてこうなった・・・・