Categories: firebase

#FJUG #firebase Firebaseの知見を共有する Firebase Meetup #6 @CyberAgent に参加してきたまとめ

firebaseについてナレッジを共有するイベントFirebase Meetup #6 @CyberAgentがCyberAgentで行われたので意気揚々とナレッジを吸収しにいきました。
これはそんなfirebase大好きっこによるまとめ。

Firestoreをざっくり紹介

Firestoreを ざっくり紹介 Firebase Meetup #6 @k2wanko
Firestoreをざっくり紹介 - Google Docs

Firestoreとは

  • 拡張性の設計はnosqlだけど階層をもったデータ構造をとれる
  • Realtime databaseとくらべると高機能なクエリ処理ができる
  • クエリをなげたら書き込んだ最新の値が取れるトランザクションも対応してる
  • リアルタイムのデータ共有がある
  • オフラインでデータを書き込むことも可能
  • アクセスが増えても予算の限りスケールさせることが可能
  • FirebaseのコンソールとGoogle Cloud Platformのコンソール2つあって、cloud controlから予算の最大値を決めることもできる
  • storageはspannerを使っている
    • spannerはgoogleが提供する高可用性DBで、MySQL並にjoinができつつ、NoSQL並の可用性があり、ストレージも無制限なDB
  • 同時接続数は100万
    • リアルタイムでデータを書き込むユーザの数
  • まだBetaなのでSLAはないので、落としたらまずいサービスには使えない
  • Android/iOS/Webなどのクライアントから直接データを書き込める
  • サーバから操作するときはpython, go, php, node.js, javaなどのSDKを使って書き込むことも可能
  • セキュリティ
    • 直接書き込むときの保護のシステムとして、Firebase Auth + Security Ruleをかけばユーザのデータは守れる
  • firestoreのリージョンがus-centralしかないが、us-east1とeurope-west3が追加された
  • マルチリージョンは、大陸を超えて分散できる、readするときは色んな国から読み取れるが、書き込むときは選んだリージョンで書き込みを行う

Firestore datastore mode

  • GCPで提供されているDBの3代目
  • 既存のdatastore apiから操作できる
  • datastore使ってた人はupgradeもすぐできる
  • datastoreに制限があったが、spannerをベースに置き換えることで制限がなくなった
  • リードしたときに最新のデータを読み取れるようになった
  • Firestoreはdatastore modeとnative modeが存在する

GCP Databaseの系譜

  • Bigtableを便利にしたのがDatastore。
  • Datastoreのトランザクションなどに制限があったが、解消したのがspannerになる
  • datastoreにあった厳しい制限が撤廃されて便利になった
  • ちなみにspannerは一月7万とかして高いのだが、firestoreはみんなでベースのspannerを使ってるのでお安く使える
  • ただし、spannerと違ってJoinなど高機能なクエリはできない。
    • 重くなるクエリはかけません。
  • Realtime Databaseのいいところを組み合わせてfirestoreがある

アプリケーションアーキテクチャ

  • firestore使わないサービスだったら、よくある構成としてDNS→Application Server→Database Serverといった構成になる
    • アクセス数が増えたらLoad Balancerを追加してApplication Serverを増やす
    • 更にアクセス数が増えたらApplication Serverを増やして、Database Serverも増やしたり、Persistent Diskも増やしたりする
  • firebaseを使うと、直接アプリケーションから、Firestoreに書き込むことができるようになる
    • Webコンテンツを表示したければFirebase Hostingを使う
    • 認証もFirebase Authもできる
    • 何かしらサーバ処理がしたければCloud functionを使う
  • 昔からよくある構成だと、サーバサイドエンジニアだけじゃなく、インフラエンジニア、アプリエンジニアなどがそれぞれ必要だが、firebaseで限るならフロントエンジニアだけいればなんとかなる

データ構造

  • ドキュメント思考のDB
  • コレクションはドキュメントを複数まとめる
  • nameやemailなど、プロパティはデータに当たる
  • Realtime Databaseはネストしたデータをとろうとすると全部とってしまうが、firestoreでは、サブコレクションという機能があり、ドキュメントの中にコレクションを作ることで、ドキュメントをとってもネストしたすべてのデータをとってしまったりはしない
    • サブコレクションは時間とともに変わるのを管理するといい
  • サブコレクションでネストしておくと、ruleを書くときに書きやすくなる
  • サブコレクションは親を消しても残り、ストレージの中に残り続けてしまうので注意

新機能について

  • cf: Better Arrays in Cloud Firestore!
    • Array-containsを使うと値が含まれているかどうかもわかれるようになった
    • arrayRemove()で配列の中の指定データを消せる
    • arrayUnionは同じ値が含まれていたら追加されない
  • Security ruleでinの追加

セキュリティルール

  • 注意点としてAdminSDKから操作するときは適用されない
  • クライアントからの読み書きを制御するためのもの
  • セキュリティルールは独自の言語で記述する

シミュレーター

  • コンソールからセキュリティルールを確認できる機能があります
  • たまに挙動がおかしいのでE2Eテストも合わせて確認したほうがいい
  • コンソールからすぐに戻せる、セキュリティルールのリストアも最近追加された

データのインポート/export

  • データのバックアップが最近追加された
  • gcloudコマンドを使ってバックアップ・リストアができるようになった
  • 保存先はGoogleCloudStorage
  • BigQueryへのエクスポートもできるので、データ分析も可能
    • 今月どれだけ投稿したかなども分析できる
    • データ大きくなるとお金かかるが、小さいデータなら無料で行ける

最後に

  • わからないことがあれば#firestoreチャンネルで質問してみよう!

FAQ

  • リージョンでjapanはくるか?
    • リージョンに関してはJapanも来るかもしれない
    • Cloud next tokyoでもしかしたら発表されるかも?
    • しかしリージョンは日本である必要もないと思ってる
  • バックアップ・リストアの利用したことあるか?だいたいデータ量はどれくらいか?
    • 大きなデータは試したことがない
    • 時間がかかるものに関してはキューに積まれて、gcloudコマンドでバックアップが完了してるかどうかを確認できる
    • 定期実行はREST API叩けばできると思う
  • 権限周りで、認証されてるけどみれてはいけないユーザIDなど、その部屋に入ってる人はみれるけどみれないなどの、すべてのエンドポイントに対して書くのは大変だとおもうが、それらをサポートするものはないか?
    • セキュリティルールは難しくて人類にはたしかにまだ早い
    • Protocol bufferというもので型を定義してセキュリティルールに書き出すものはある
    • それをつかえばstringであるといった制限はできる
    • permissionに関しては良いツールはないのでゴリゴリかくしかない
    • メンバーに参加しているしていないに関しては、inというセキュリティルールを使えばユーザIDが存在するかなどを書いてreadできるかなどできる
    • firestoreはreadだけにして、書き込みはcloud functionなどのサーバからやるのもいいかも
    • 内容も複雑化するならサーバでやるという手もある。
    • コストで考えるならfirestoreを使うのはありで、スタートアップで使うのはいいと思う
  • 継承されたりするとわからなくなるので、エンドポイントごとに誰がアクセスできるか可視化できればいいきがした。
    • 継承されるのはrealtime databaseだけでfirestoreで継承させるのは**を書いて明示的に示す必要がある
    • 並列にデータを並べるようにしたほうがいいと思う
    • ディレクトリを表現するのではなく、ラベルで表現するなどの工夫をしていく必要があると思う

機材管理ツールをFirebaseで構築しようとした話

抱えていた課題

  • 機材が誰のものかわからない
  • 何がセットで入ってるのかわからない
  • いつ使ったかがわからない
  • 貸した人がわからない

なぜfirebase?

  • 一般的だとawsやvpcなどで作ったりするが、できるだけお金をかけずに作りたかった
  • 手軽にアプリケーション作りたかった
    • サーバの環境やDBの構築に時間をかけたくなかった
  • Realtime DBを使ったことはあったが、Firestoreをつかってみたかった

課題の解決方法

  • 機材が誰のものかわからない → 機材のQRコードを付けて読み取るとwebページが表示されるようにする
  • 何がセットで入ってるのかわからない → 1つの機材に何の機材が同梱されているかをデータ化する
  • いつ使ったかがわからない → 機材を使うときにQRコードを読み込むことで使用履歴を管理する
  • 貸した人がわからない → QRコードを読み取った際に、現在の場所を記録する

機材タグ

  • 機材ごとにタグを発行する。
    • QRコードは機材ごとに固有のURLが入っている
    • 手入力でも入力できるURLの短さにしている

Androidアプリとwebサイト

  • 機材を管理する人が使うためのAndroidアプリ
    • QRコードを読み取る
      • →GPSの情報を付与する
    • 機材の追加や編集を行う
  • QRコードを読み取ったときに開くWebサイト
    • 機材の詳細が表示されてアプリをもってないひとでも使えるようにしている
    • 紛失時にQRコードから連絡先を知ることができる

使用例

  • 機材を使うときはQRを読み取って使用履歴を登録
  • 資材を探したいときは、機材の一覧をみて読み取り履歴を確認する
  • 中身が知りたい、紛失した時は、機材の詳細のWEBページを表示する

データ構造

  • 複数のグループで利用できるような構造にしている
  • 短縮URLに関しては(ショートカット)は全グループで共通にしている
  • 機材はグループの下にネストされている
- /users/{id}/devices/{id}
- /groups/{group}
    - /addresses 家など住所が登録できる
    - /euipments 機材
    - /scans 機材の利用履歴
    - /tags タグリスト
- /shortcuts/{code} ショートカットコード

ユーザ

  • Firebase authenticationでサインインしたあとに作成する
  • belongingGroupsはユーザが所属しているグループ
    • この所属しているグループ以外には書き込めないSecurityGroupにしている

機材

  • 機材の名前、画像のパス、同梱する機材、タグなどを入れる
    • 同梱する機材はArray(Reference(Equipments))として保存している
  • tagsはarrayのString

ショートカット

  • 機材のreferenceとgroupのreferenceで構成される

Androidアプリ

  • 機材一覧、機材詳細、スキャンの画面で分かれる
  • androidアプリを使うときのライブラリ

Webサイト

  • Reactを使って開発
    • ホスティングはFirebaseHostingを使用
  • 必要なAPIはCloudFunctionsでAPIを構築

マスターデータの投入

  • すべての機材をスマホやブラウザのフォームで入力するのは大変なので、スプレッドシートでデータを入力できるようにした。
  • ボタン一つでFirestoreにデータを入れられるようにgrahamearley/FirestoreGoogleAppScriptを使用した
  • スプレッドシートでツールのボタンを押すだけでfirestoreの更新ができる
  • FirestoreGoogleAppScript自体はinsertやupdateの関数があるので、呼び出すところはGASを使って書かないといけないが、「,」区切りのものをarrayにしたりと、わりと柔軟にかける

つまづいたところ

  • FirestoreのRUle SimulatorがReferenceをうまく扱えない
  • FirestoreGoogleAppsScriptで特定のキーのみ更新することができない
    • オブジェクトを1回手得してから更新する
  • 配列の中身に対してカテゴリを実行することはできないのでMapでやるとよい
    • Categories: [“a”, “b”, “c”] → Categories: [“a”: true, “b”: true , “c”: true]
    • CloudFunctionを利用して、onWriteイベントで、データが更新されたタイミングでタグを更新するようにした

まとめ

  • firebaseを使ってすばやくサービスが作れる
    • Firestore/hosting/functionが便利
    • androidアプリを作るのもライブラリがあって便利
  • スプレッドシート経由でデータを入れるのも便利
    • FirestoreGoogleAppsScriptは読めるコード量
  • Referenceはのりで使うと痛い目を見る
    • あまりメリットは感じなかった
    • reference分ゲットしないといけない。

QA

  • reactのwebサイトを使うときにapiはcloud function使ってやったが、直接js sdkやらなかったのはなぜか?
    • 一回でまとめられるリクエストはまとめたかった
    • セキュリティーグループをしっかりすればいいと思うが、sdkを使っても取れない情報を取りたかった。
  • ステージング環境はどうしたか?
    • 作っていないです。
  • 画像のURLがあるが、画像はどうしているか?
    • クライアントで画像を読み取っている
    • storageに上がったものを実際に使ったりはしていない
  • インポートするときにrefereneはどう解決するのか?
    • データ的に最終的な関数に、stringで/database/~とstringで渡すとreferenceとして解決してくれる
    • idを,区切りでかくとstringにしてreferenceにして登録してくれる

@mogmetの所感

firestoreの概要だけでなく、新機能や注意点など幅広く知見を得られたとてもいい勉強会でした。
array周りの情報に関してはとくに目からウロコな情報だったのでとてもよかったです。

セキュリティルールに関しては人類にはまだ早いと称されていますが、これからきっとどんどん良くなると信じております!

cloud functionでAPI化してやるという手法も紹介されていましたが、せっかくのfirestoreの利点(リアルタイム共有や、書き込み速度など)が損なわれてしまうので、やるならばがっつりセキュリティルールを頑張ってでもfirestoreをクライアントからいじりたいと思っています。

mogmet

View Comments