Firestoreを利用したブログサービスの実装例

記事
IT・テクノロジー

Firestoreを利用したブログサービスの実装例

この記事では、Firestore を利用して、投稿記事のメタデータを保存した場合の実装例を紹介します。今回紹介する方法では、投稿記事を表示する場合以外は、Firestore からメタデータを取得して表示するため、投稿数が多くなっても素早い記事の一覧表示が可能です。


投稿記事の一覧の取得

Firebase のデータベースである、Firestore から投稿記事のメタデータを取得します。 投稿記事のメタデータは、記事の投稿時に、Firestore のデータベースに保存して、オリジナルの Markdown のファイルは、Firebase のストレージに保存してある前提です。 メタデータを保存している Firestore のコレクションは「sample」です。

import {
  collection,
  doc,
  onSnapshot,
  query,
} from "firebase/firestore";
import { db } from "../lib/firebase";

getList() {
      const my_query = query(collection(db, "sample"));
      const unsub = onSnapshot(my_query, (query_snapshot) => {
        this.docs = [];
        for (let i = 0; i < query_snapshot.size; i++) {
          const doc = query_snapshot.docs[I];
          this.docs.push(doc);
        }
      });
},

この例では、「onSnapshot()」を利用しているので、このコレクションの内容が更新(追加、削除、変更)された際に、ドキュメントを再読み込みして表示するデータを更新するようにしています。

これを、この Vue の「部品」が作成された際に Firebase から取得するようにします。

created() {
    this.getList();
}

投稿の一覧の表示と選択の処理

取得した投稿の一覧の表示と投稿が選択された場合の処理です。 投稿時に Markdown のメタデータと、Firebase ストレージの投稿した Markdown のファイルにアクセスするためのリンク(URL)を取得して Firestore に保存しているので、選択されたリンクを使って、Firebase のストレージに保存されているファイルの中身にアクセスして、記事を表示する処理になります。

selectItem(url) {
      fetch(url).then((res) => {
        res.text().then((rawtext) => {
          this.htmlText = getHTML(rawtext);
        });
      });
}
Markdown の記述から HTML に変換する処理は以前に紹介した、「gray-matter」と「marked」のモジュールを使って行なっています。

import matter from "gray-matter";
import { marked } from "marked";
export function getHTML(text) {
  const processed = matter(text);
  const html = marked(processed.content);
  return html;
}
これらの情報を Vue の HTML の記述部分で表示します。 Vue の HTML の部分の例です。

<template>
  <div>
    <table>
      <thead></thead>
      <tbody>
        <tr v-for="doc in docs" :key="doc.id">
          <td>
            <a id="{{doc.id}}" @click="selectItem(doc.data().url)">{{
              doc.data().name
}}</a>
          </td>
        </tr>
      </tbody>
    </table>
    <div v-html="htmlText"></div>
  </div>
</template>
ここのリストされている名前がクリックされたら、上の「selectItem()」を呼び出すようにします。

全体のコードは?

こちらが、Javascript 部分の全容です。変数は、「docs」と「htmlText」の二つです。 投稿をアップロードする管理部分があれば、表示の部分はとてもシンプルです。

<script>
import {
  collection,
  deleteDoc,
  doc,
  onSnapshot,
  query,
} from "firebase/firestore";
import { db } from "../lib/firebase";
import { getHTML } from "../lib/text";
export default {
  data() {
    return {
      docs: [],
      htmlText: "",
    };
  },
  methods: {
    getList() {
      const my_query = query(collection(db, "sample"));
      const unsub = onSnapshot(my_query, (query_snapshot) => {
        this.docs = [];
        for (let i = 0; i < query_snapshot.size; i++) {
          const doc = query_snapshot.docs[I];
          this.docs.push(doc);
        }
      });
    },
    selectItem(url) {
      fetch(url).then((res) => {
        res.text().then((rawtext) => {
          this.htmlText = getHTML(rawtext);
        });
      });
    },
  },
  created() {
    this.getList();
  },
};
</script>
管理上考える事は?
以上が Firestore を使って投稿した記事の一覧を表示して、選択された記事の内容を表示する実装例です。 ところで、このような形で実装する場合には管理上に考えることがあります。

その中の一つが、データの削除です。

この実装例では、二つのデータがあります。一つは、Firebase ストレージに保存されている投稿の原稿となる Markdown のファイルと、Firestore に保存されている、投稿の原稿から抽出したメタデータです。

このデータを完全に削除するには、この二つのデータを削除する必要があります。

しかし機能上は、Firestore のデータを削除すると利用者からは、原稿のファイルは存在しないように見えます。つまり、機能的には、投稿の Markdown を削除する必要がありません。

この Markdown のファイルを削除しなければ、データベースの普及も可能です。

このことを考えると、

データの削除はデータベースとストレージをわけて行なった方が安全
一時的に、特定の原稿を利用者から見えなくする事が可能
という事になります。

Firebase のストレージからデータを取得している場合、投稿の Markdown を削除する必要がありますが、この様にデータベースを利用することで、より柔軟性のある実装が可能になります。

こうした事を考慮して管理ツールを開発するとより、使いやすく、管理しやすいサービスが実現できます。

まとめ
投稿原稿のメタデータを Firestore に保存する事で、処理時間だけではなくて、サービス自体をより柔軟に実装可能になります。良い例が、実際に Firebase のストレージに保存されているファイルを消去せずに利用者からは見えなくしたりなどの管理も可能になります。

特にブログのサービスでは、場合によっては特定の記事を隠したい場合もあります。そうした場合でも、実際にファイルを消去しなくても、こうした操作が可能になるのはサービスを運用する上で便利な特徴です。

サービスを設計する際は、機能だけではなくこうした点も考慮するとより便利なサービスを実現できます。

今回紹介した例では、Firebase の「onSnapshot()」を使って、新しい記事が投稿された際は一覧の表示を自動更新することも実装しています。これも、利用者には便利な機能です。

次回は、管理ページの方も改善してみます。
サービス数40万件のスキルマーケット、あなたにぴったりのサービスを探す