‘Firestore’ タグのアーカイブ

murave

FirestoreのServerTimestampさん

有能!

サーバー側で採時するので集計対象の抽出などに安心して使用できます。
これのおかげで必要なデータ取得数を大幅に削減できています。
Firestoreだとデータ取得数は速度や効率だけでなく課金に直結しますしね。

管理画面でデータを時系列に並べたりするのにも便利なのでドキュメント登録時には必ず入れておいたほうが良いくらいの有能さです。

Webでは

import firebase from '~/plugins/firebase'

payload.createdAt = firebase.firestore.FieldValue.serverTimestamp()
await db.collection('コレクション名').add(payload)

(Functionsなど)node.jsでfirebase-adminを使用する場合は

const admin = require("firebase-admin");

const serviceAccount = require("サービスアカウントの鍵.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});

admin.firestore().collection("コレクション名").doc("ドキュメントのキー").set({
updatedAt: admin.firestore.FieldValue.serverTimestamp()
});
といった感じでサーバー側でTimestampを投入するように指示できます。

でも注意点が。

登録直後にドキュメントを取得するとTimestampが入ってない状態で返ってきます(2019年3月)。await等で完了をまっても、です。
ただしこれはフロントエンドからの取得の話でonCreateで起動されたFunctionsではさすがにちゃんと入っているようです。

フロントエンドで登録直後にデータを取得し(Server)Timestampを利用するには採時されるのを待つ必要があります。タイミングの問題ってことです(;´Д`)

私の場合は操作ログ記録のための変更後のドキュメント取得でしたので、ログ登録という処理の性質上ユーザーから見える必要はないので非同期に500msディレイして取得・登録処理を行うようにしました(lodashのdelayを利用)

なんか記事書いててもホントかよって感じですが。

murave

Firestoreのセキュリティルールのこと

バックエンドをFirebaseでSPAのシステムを作る場合、データを守る砦はデータベース(今回はFirestore)のセキュリティルールです。
Authenticationのログイン情報とFirestore上のユーザー情報を紐付けし権限によりドキュメントへのアクセスを制限するなど、適切な設定しなければなりません。

service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
これは「ログインしているユーザーはフルアクセス」という最低限設定しておくべきルールです。開発中はお世話になりました。
しかし最終的にはもっとこまかく制限をかける必要がありますから、それを前提にデータ構造を設計しておいたほうが良いです。

例として今回作ったシステムのデータ構造とセキュリティルールの一部について解説します。

今回のシステムでは権限による制限が必要だったのでFirestoreにemailをキーとするコレクション、usersを作成し権限情報roleをもたせました。セキュリティルール中でAuthenticationのログイン情報からemailを取得できますので紐づけが可能です。

usersのドキュメント例(権限に関するroleのみ)

murave@hoge.var: {
role: "admin"
}
これを利用してアクセス制限を行います。一部ルールを例示します。

firestore.rules

service cloud.firestore {
match /databases/{database}/documents {
function getUser() {
return get(/databases/$(database)/documents/users/$(request.auth.token.email));
}

match /users/{email} {
allow get: if request.auth != null;
allow read, write: if getUser().data.role == 'admin';
}

match /journals/{journal} {
allow read: if getUser().data.role in ['viewer', 'admin'];
allow create: if request.auth != null;
}

match /summaries/{summary} {
allow read: if request.auth != null;
allow write: if getUser().data.role == 'admin';
}
}
}
この設定は以下の制限・意図となっています。

  • usersはログインしていればドキュメントの(個別)取得は可能。一覧取得、書き込みは管理者(admin)のみ可能。
    ログインしたユーザーが自身の権限情報を取得できる必要がある。
  • ユーザー情報は管理者が管理する。

jornalsへの新規登録はログインしていれば可能。読み出しは閲覧者(viewer)と管理者(admin)が可能。

  • これは集計前の生データなので、ログインしたユーザーすべてが入力する可能性がある。
  • 閲覧者と管理者は登録された生データの分析を行うことができる。

summariesはログインしていれば読み出しは可能。書き込みは管理者(admin)のみが可能。

  • jornalsを集計したデータでユーザーは基本的にはこの集計されたデータを見る。
  • 集計処理はjornalsへのドキュメント新規登録をトリガーとして実行されるFirebase側のFunctionで行われる。
  • 管理者は集計を修正できる。

集計処理はFirebaseのFunctionsを利用しサーバー側に委譲しており、一般・閲覧ユーザーの権限を絞ることが可能となっているのもミソです。

getUser()はAuthenticationのログイン情報のemail(request.auth.token.email)からusersのドキュメントを取得する関数です。内部で使用しているget()等、組み込みの関数には使用回数制限があることに注意してください。同じドキュメントの取得では使用回数は増えないなど独特のルールがあるので意識して、制限を超えないような構造にしなければなりません。

適切なセキュリティルールで安全なFirestoreライフを!