taisablog

taisa's engineer blog

JavaScript

Firebase Cloud Firestore 使い方の勘ドコロ

投稿日:


FirebaseのCloud Firestoreを扱う際、本家ドキュメントが充実していて検索すればすぐに出てくるのでそれほど困ることはありません。ただ、最初の入りとしてFiresotreのDocumentって何? となったり、docdocRefcityRefcityDocRefsnapShotdocs など、本家ドキュメントの中でも若干変数名の書き方が異なっていたりします。その為、慣れてくれば大丈夫ですが、慣れるまで毎回どう書くんだっけ?と検索することが多かったので、自分なりに解釈して整理してみました。Firestoreを扱える言語は様々用意されていますが、ここでは、JavaScript(Nuxt.js)を例に進めていきます。(セットアップは省きます)

参照元:https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ja

Firestoreの基本的な考え方

基本的な考え方は、正にこの図にあるように「フォルダ(collection)」「ドキュメント(document)」「データ」という構成になっています。

参照元:https://firebase.google.com/docs/firestore/data-model
これをFirestoreの管理画面でみるとこのようになります。

これを「フォルダ(collection)」「ドキュメント(document)」「データ」に当てはめてみるとこのようになります。イメージとしては、本棚にフォルダが並んでいてフォルダを選択するとフォルダの中のファイル一覧がみることができ、あるファイルを選択するとそのファイルに書かれている内容をみることができるという感じです。

◯◯Refとは

本家ドキュメントをみると、◯◯Refという変数がよく出てきます。これはその名の通り「参照」です。つまり本棚にあるフォルダ(collection)やフォルダ内のドキュメントを選択した状態です。この時点ではまだ参照なので取得はしていません。usersコレクションを選択した状態であればuserRefusersコレクションのドキュメントを選択した状態であればuserDocRefといった変数をつけると分かりやすいと思います。(本家ドキュメントではそのようなルール決めはありません。)

userRef = db.collection('users')
userDocRef = db.collection('users').doc('YLu7bG7PcRNYhAg3F6MY')

これらを踏まえて、実際にデータの取得、追加、更新、削除のコードを書いてみます。ここではあえて◯◯Refのように変数を使っています。

コレクション配下のドキュメントデータをすべて取得する

usersコレクションを参照した状態で、get().then()を呼び出すとその時点のドキュメント一覧(snapShot)が取得できます。ドキュメントは1つしか存在しない可能性もありますが、ドキュメント一覧なのでforEachでループすることで全データを取得することができます。ユーザIDはデフォルトでドキュメントに振られるIDです。

const db = firebase.firestore();
let userRef = db.collection('users')
userRef.get().then((snapShot) => {
  snapShot.forEach((doc) => {
    this.users.push({
      user: doc.data(),
      user_id: doc.id
    })
  })
})
ユーザID ユーザ名 ユーザメールアドレス
{{user.user_id}} {{user.user.name}} {{user.user.email}}

参考:https://firebase.google.com/docs/firestore/query-data/get-data?hl=ja

コレクション配下のドキュメントデータをフィルタして取得する

フィルタするのにwhereを利用することができます。whereで対象を絞った後、同様にget().then()を呼び出すとフィルタしたドキュメント一覧が取得できます。

const db = firebase.firestore();
let userRef = db.collection('users')
userRef.where('name', '==', '山田太郎1').get().then((snapShot) => {
  snapShot.forEach((doc) => {
    this.filteredUsers.push({
      user: doc.data(),
      user_id: doc.id
    })
  })
})
ユーザID ユーザ名 ユーザメールアドレス
{{user.user_id}} {{user.user.name}} {{user.user.email}}

参考:https://firebase.google.com/docs/firestore/query-data/get-data?hl=ja

単一のドキュメントデータを取得する

単一のドキュメントデータを取得するには、doc()IDを渡し、get().then()を呼び出すと指定したドキュメントのデータが取得できます。この場合、doc()で単一のドキュメントを指定しているので、取得できるのは一覧ではなく指定したドキュメントの値となります。

const db = firebase.firestore();
let userRef = db.collection('users')
userRef.doc('YLu7bG7PcRNYhAg3F6MY').get().then((doc) => {
  this.user = doc.data()
  this.user.user_id = doc.id
})

これは以下のようにも書くことができます。

const db = firebase.firestore();
let userDocRef = db.collection('users').doc('YLu7bG7PcRNYhAg3F6MY')
userDocRef.get().then((doc) => {
  this.user = doc.data()
  this.user.user_id = doc.id
})
ユーザID ユーザ名 ユーザメールアドレス
{{user.user_id}} {{user.name}} {{user.email}}

参考:https://firebase.google.com/docs/firestore/query-data/get-data?hl=ja

ドキュメントを新規追加する

ドキュメントを新規追加するには、add()またはset()を使います。ドキュメントIDをランダムに完全に新規で作成する場合はadd()を利用します。ドキュメントIDを任意の値に指定したい場合はset()を指定します。set()は、既存のドキュメントIDを指定するとドキュメント全体を更新する処理となります。

const db = firebase.firestore();
let userRef = db.collection('users')
// 完全新規で追加する場合
userRef.add({
  name: '山田花子1',
  email: 'sample1@sample.com'
})
// ドキュメントIDを指定して新規追加する場合
userRef.doc('new-user-id').set({
  name: '山田花子2',
  email: 'sample2@sample.com'
})
// 既存のIDを指定してドキュメントの値を更新する場合
userRef.doc('YLu7bG7PcRNYhAg3F6MY').set({
  name: '山田花子3',
  email: 'sample3@sample.com'
})

参考:https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ja

ドキュメントを更新する

ドキュメント全体を上書きせずにドキュメントの一部のフィールドを更新するには、update()を使います。

const db = firebase.firestore();
let userRef = db.collection('users')
userRef.doc('YLu7bG7PcRNYhAg3F6MY').update({
  name: '山田花子1'
})

参考:https://firebase.google.com/docs/firestore/manage-data/add-data?hl=ja

ドキュメントを削除する

ドキュメントを削除するには、特定のドキュメントIDをしていしてdelete()を呼び出します。

const db = firebase.firestore();
let userRef = db.collection('users')
userRef.doc('2YkjKlEoEQtH0tBJnByr').delete()

参考:https://firebase.google.com/docs/firestore/manage-data/delete-data?hl=ja

まとめ

ある程度がっつり書いていけばすぐに慣れますが、ちょこちょこ書いていたので書くたびにドキュメントを参照するというのを何回もやっていたのでまとめてみました。自分なりにまとめたものなので誤っている解釈などがあれば指摘して頂ければ幸いです。

-JavaScript
-

執筆者:

関連記事

おれ的フロントエンド速習コース

3ヶ月でフロントエンド向上させるにあたって取り組んだことを書く。 フロントエンドって? どこからどこまで?何を指してる?と引っかかる人がいるかもしれないけどそこら辺はなんとなくお察しください。 3ヶ月前まで JSとjQueryのみ 毎回ノリで書いていた(もちろんカオスにならないように最大限工夫はしてるけど) 流れが早いからモダン情報のキャッチアップはタイミングを見計らっている けど2017年中にはなんとかしたい やるなら一気にやりたい 始める前まではこんな感じだったけど、そろそろいってもいいかな?ということでやり始めた。 速習後 もともとは既存プロダクトをどうにかするつもりで始めていたけど、タイミングよく新規プロダクトを立ち上げることになったので採用した。何もしてなかったらかなり勇気が必要だったと思う。 ES6 React VueJS Webpack Babel PostCSS Go PHP(継続) 3ヶ月でやった事 JavaScript(ES5)を速習する ES6を速習する React(でSPAを)速習する マークアップを速習する Podcastで速習する 勉強会で速習する チームメンバーと速習する JavaScript(ES5)を速習する オライリー本で速習 JavaScriptパターン ―優れたアプリケーションのための作法 Amazonより 「JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス」や他の本もいいけど個人的にはこの本がお薦め(発売時期がよい)。 ※デザインパターンの章は他に「JavaScriptデザインパターン」という書籍があるしここでは読み飛ばしてもよいと思う。 ES6を速習する WEB+DB PRESS Vol.87で速習 WEB+DB PRESS Vol.87 Amazonより 非常に分かりやすく端的に説明されていてとてもよい。 (こんなツイートも↓) 『JavaScript: The Good Parts』と『WEB+DB PRESS Vol.87 第1特集』のあわせて250ページ未満でES6までの全体像をつかむ速習コースのご提案 http://t.co/doPQ7V4enw http://t.co/NKTGz3syk7 — Takuto Wada (@t_wada) 2015年8月10日 React(でSPA)を速習する WEB+DB PRESS Vol.97 Amazonより React+Flux、クライアントサイドルーティング、サーバサイドレンダリング、webpackについて丁寧に説明されている。他にもマネジメントやPythonに関する内容があってとても読みごたえがある。 すぐに「理解できた」という訳にはいかない Reactはそれなりに初期学習コストがあるので以下のことを繰り返しながらじっくり理解を進めていった。 サンプルコードを動かす 本家サイトチェック ブログ記事チェック 今話題のReact.jsはどのようなWebアプリケーションに適しているか?(お薦め記事) サンプルコードを作る Web+DB PRESS見直す マークアップを速習する マークアップも一人でできるようになりたいというメンバーが多かったのもあり、社内のUI/UXデザイナーにハンズオンをしてもらった。このハンズオンの目的としては何から手をつけていいか分からないという状況から脱却して自分でもなんとか勉強できる状態にすることでこれだけでなんとかしようというものではない。 関連リンク – 初心者向けざっくりHTML/CSSコーディングハンズオン資料 – 社内エンジニア向けにマークアップハンズオンを開催しました その他の方法 Podcastで速習する 現場.fm 現場.fm というフロントエンドの現場について話すラジオを始めた 勉強会で速習する コミュニケーションしながら疑問点を解決してもらえたのでとても助かった。他にもReact、VueJS、Angular以外も含めたフレームワーク発表会をやったりした。またそれをうけてあたらめてReact、VueJS、Angularはいいなと実感した。 チームメンバーと速習する 今QはJSをやろうと全員で決めた(※この間業務でJS触る機会は0だった) 情報共有しやすい ここでもチームメンバーで分担してReact、VueJS、Angularを調べて発表会をした チームメンバーのJSに対する意識が全体的に変わって導入障壁が低くなった まとめ 業務でJS触る機会が0だったとしても3ヶ月あれば結構イケる 他にやりたいことができてもなるべく我慢してJSやるの大事 …

Vue.jsで外部APIを使ったTODOリストを作ってみた

APIを使ったTODOリストをVue.jsで作ってみました。TODOリスト用のAPIは以前書いたこちらのAPI「Go言語 GORM+GinでTODOリストのAPIを作ってみた」を利用します。CORSを全て許可しているのでどこからでも叩けるようになっています。 できたもの できたものはこちらです。http://vuejs.taisablog.com/todo APIのエンドポイント APIのエンドポイントは以下としました。 URL http://gin.taisablog.com/api/v1/ GET /todo // 一覧表示 POST /todo // 新規作成 GET /todo/:id // 編集画面表示 PUT /todo/:id // 編集(今回未使用) DELETE /todo/:id // 削除 TODOリストの処理 プロジェクトはvue-cliで作成し、APIはaxiosを利用しました。componentsにTodo.vueファイルを作成しそこにすべての処理を書いています。 インポート import axios from ‘axios’ const NOT_STARTED = 1 // 未対応 const STARTED = 2 // 対応中 const FINISHED = 3 // 完了 data function name: “Todo”, data() { return { todoList: [], inputField: ”, isActive: false, baseUrl: ‘http://gin.taisablog.com/api/v1/’ } }, created function created() { this.getTodo() }, methods : 一覧を取得する async getTodo() { try { let response = await axios.get(this.baseUrl + ‘todo’) this.todoList = response.data } catch (e) { console.log(e) …

Rust+WebAssembly で Hello, World!

以前 Rust をはじめてみよう!という記事を書いた。今回は Rust + WebAssembly を使って Hello, World!の出力をやってみた。 WebAssembly について まず WebAssembly とは何か。本家サイトの Overview をみてみる。ここにある通り、WebAssembly(WASM)は C/C++/Rust などの高級言語を使って開発をしバイナリ形式で動かすことができる。その為 Web 上で高速に動かすことができる。とりわけゲームなどの実行速度が求められるような分野で有効になる。Chrome、Firefox、Safari、Edgeで利用が可能。 WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable target for compilation of high-level languages like C/C++/Rust, enabling deployment on the web for client and server applications. https://webassembly.org/ よくデモに出てくる Unity を使った動画 https://webassembly.org/demo/Tanks/ Youtube動画 再生回数が一番多い動画をあげておく。2018年2月の動画ですごく分かりやすく説明されている。 Rust+WebAssembly のドキュメント https://rustwasm.github.io https://github.com/rustwasm ここからは以下の記事を実際にやってみる。実際にほぼそのまま実行しているだけなので以下についてはリンクをチェックするだけでも良いです。 https://rustwasm.github.io/book/game-of-life/hello-world.html 事前準備 参考URL:https://rustwasm.github.io/book/game-of-life/setup.html rustup を使って rust をインストールする curl https://sh.rustup.rs -sSf | sh source $HOME/.cargo/env source $HOME/.cargo/envは .zshrc などに記述しておくとよい wasm-pack インストール wasm-pack を使うとビルド・テスト・公開などが簡単にできる curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh cargo-generate インストール cargo-generate を入れるとcargo …

Nuxt.js v2.9のリリース情報とDiff

2019年8月20日にNuxt.jsのバージョンが2.8.1から2.9へがリリースされました。2019年9月19日時点ではバージョン2.9.2まであがっています。本投稿ではリリース内容と変更点が見れるように2.8.1から2.9.1のソースのDiffと変更されたファイル一覧を載せておきます。変更ファイル数は、examplesやtestを除くと約142ファイルでした。またバージョンが上がっただけ、関数にスペースが追加されただけのファイルも多く、それを除くともっと少なくなります。本リリースでの大きな変更はImportant Notesの中でもTypescript関連の変更が個人的には大きいと思います。Nuxt Typescriptの導入やMigrationはリリースノートにあるページの Setup、Migration from Nuxt 2.8 を見れば簡単に行えます。(本記事の一番下でも試しにやってみました。) リリースノート nuxtjs.orgDue to a known problem (webpack/webpack#8656, #4869, #4839) users of npm should either remove package-lock.json and reinstall before upgrade or use npm update acorn –depth 20 && npm dedupe after upgrading to 2.4.0. users should have no problems but removing yarn.lock still recommended before the upgrade process. Diff v2.8.1からv2.9.2のDiffをつくってみました。 v2.9.2 diff by taisa831 · Pull Request #1 · taisa831/nuxt.jsTypes of changes Bug fix (a non-breaking change which fixes an issue) New feature (a non-breaking change which adds functionality) Breaking change (fix or feature that would cause existing functionality to change) Description …

no image

Vue.js+TypeScriptで外部APIを使ったTODOリストを作ってみた

Vue.jsで外部APIを使ったTODOリストを作ってみた に続き、それのTypeScript版を作ってみました。TODOリスト用のAPIは以前書いたこちらのAPI「Go言語 GORM+GinでTODOリストのAPIを作ってみた」を利用します。CORSを全て許可しているのでどこからでも叩けるようになっています。TypeScriptを書くのは今回が初めてなので、誤っている箇所やもっとよい書き方などがあれば指摘して頂ければと思います。 できたもの できたものはこちらです。http://vuejs-ts.taisablog.com/todo <div class=”graybox”> <div class=”clearfix”><figure><a href=”http://52.196.213.4/wp-content/uploads/2019/08/063dff08aea69d0ee7c6cea19de29030.png”><img class=”alignleft size-full wp-image-1684″ src=”http://52.196.213.4/wp-content/uploads/2019/08/063dff08aea69d0ee7c6cea19de29030.png” alt=”” width=”600″></a></figure></div> </div> APIのエンドポイント APIのエンドポイントは以下としました。 URL http://gin.taisablog.com/api/v1/ GET /todo // 一覧表示 POST /todo // 新規作成 GET /todo/:id // 編集画面表示 PUT /todo/:id // 編集(今回未使用) DELETE /todo/:id // 削除 プロジェクト作成 vue-cliを使ってプロジェクト作成をしました。プロジェクト作成のコマンドを打つと、色々と聞かれますが、TypeScriptを利用する為にManually select featuresを選択し、TypeScriptをONにします。ここではRouterもONにしました。 % npm install -g @vue/cli % vue create my-project default (babel, eslint) ❯ Manually select features vue-cliでできたプロジェクトのsrc配下の構成は以下となっています。今回はそこにTodo.vueとTodoList.vueを追加して実装しました。views配下で実装するだけでも大丈夫ですが、今回はあえてviews/Todo.vueからTodoList.vueコンポーネントを呼び出す形としました。 . ├── App.vue ├── assets │   └── logo.png ├── components │   ├── HelloWorld.vue │   └── TodoList.vue ← 新規追加 ├── main.ts ├── router.ts ├── shims-tsx.d.ts ├── shims-vue.d.ts └── views ├── About.vue ├── Home.vue └── Todo.vue ← 新規追加 views/Todo.vue TodoList.vueコンポーネントを呼び出します。 …