Next.js と FireSroreの連携

ツイート
2021年07月12日
2021年07月16日

状況/バージョン

  • Next.js v11.x
  • Firebase Google認証確認済

FireStoreの概念

ファイルシステムに近い感覚でデータを管理する仕組みになっている。

説明
コレクションフォルダのような概念
ドキュメントファイルのような概念
データファイルの中身
Referenceドキュメントやコレクションへのパス情報だけで、中身を持っていない。
データの追加、更新、削除はReferenceに対して行う

モデルの作成

User(users)
name文字列
Website(websites)
title文字列
Article(articles)
tilet文字列
website_idReference型

APIルートで呼び出すか否か

  • そもそも、FirebaseをAPIルートで呼び出す必要があるか疑問がある。
  • /lib/*などにまとめて置く案もある。
  • サーバ側のみでしか実行できないAPIを呼び出す時に、 /pages/apiを使用するのも良いかもしれない。(ex) アカウントの削除, 重たい処理 etc)

また、APIルートを使用すると、FireStoreサーバ <-> Vercel API(AWS)間の距離も気になるところ。

下準備

modelsapiルート,authなど複数に渡って、呼び出すのでFirebaseの設定だけ切り出しておきます。

lib/firebase.js
import Firebase from 'firebase/app' import 'firebase/auth' // importしておく import 'firebase/firestore' // importしておく const config = { apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL, projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, storageBucket: process.env.FIREBASE_STORAGE_BUCKET, messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID, appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID, } if (!Firebase.apps.length) { Firebase.initializeApp(config) } export const firebase = Firebase export const auth = firebase.auth() export const db = firebase.firestore()

ドキュメントを取得する

ドキュメントを取得する - Firebase

js
const db = firebase.firestore() const userRef = await db.collection('users').doc('xxxxxxxxxxx') const userDoc = await userRef.get() if (!userDoc.exists) { console.log('No such document!') } else { const userData = userDoc.data() console.log('Document data:', userDoc.data()) }

ドキュメント/Reference型の取得

作成したモデルクラスarticle.jsで呼び出します。名前空間の関係でクラス名はArticleModelとなっています。

models/article.js
static async get(limit = 20) { const articlesRef = await db.collection('articles').limit(limit).get() const articles = await Promise.all(articlesRef.docs.map(async (articleRef) => { // NOTE: Reference型 をそのままページに返すと 「serialized as JSON」 エラーになる // NOTE: Reference型 は Object型 で返ってくる // console.log('typeof: ', typeof a.website_id) const article = articleRef.data() console.log('article: ', article) // Reference型なので、取得するには get() すれば良い const websiteRef = await article.website_id.get() const website = websiteRef.data() console.log('website: ', website) // TODO: Classで返すか検討する return { description: article.description, image_url: article.image_url, title: article.title, url: article.url, website: website } })) return articles }

ポイント

呼び出し側

pages/idnex.js
import ArticleModel from 'models/article.js' export async function getServerSideProps() { const articles = await ArticleModel.get(20) return { props: { articles: articles } } }

ドキュメントを追加する

  • add は、ドキュメント追加時にIDを自動で付与
  • set は、ドキュメント使い時に任意のIDを指定して付与

ドキュメントの確認と追加

js
const { uid, displayName, email, photoURL } = req.body const userRef = db.collection('users').doc(uid) const doc = await userRef.get() if (doc.exists) { const userData = doc.data() res.status(200).json(JSON.stringify(userData)) } else { await db.collection('users').doc(uid).set({ name: displayName }, { merge: true }) const docRef = await db.collection('users').doc(uid) const doc = await docRef.get() const userData = doc.data() res.status(200).json(JSON.stringify(userData)) }

ドキュメントIDはupdateすべきではない

How to update the document ID in firebase firestore? [duplicate]

Firebase Authenticationでは、ユーザーを一意に管理できるらしい。このデータとFireStoreのUserを一意にできると解決する。

Firebase Authenticationのデータ

データ説明
ID
プロバイダ
作成日
ログイン日
ユーザーID

Firebase AuthenticationのユーザーIDをusersコレクションのドキュメントIDとして使用する。

Google認証から取得できるデータ

Google認証から取得できるデータは以下の通り

データ説明
displayNameGoogleアカウントの名前
emailGoogleアカウントのメールアドレス
photoURLGoogleアカウントのアバター