GatsbyJSのブログに検索機能を実装してみる

GatsbyJSのブログに検索機能を実装してみる

目次

プラグイン?

検索フォームを実装するには、どうしたらいいか?

公式サイトには Search の項目に、プラグインが 3 つ表示されています。

人気なのは、Algolia なんですかね?

う〜ん、プラグインを使わない方法はないものか? と思い、調べていくと…

全文検索?

Algolia の様に全文検索した方がいいよなぁ…とは思いつつも、個人ブログだからそこまでやる必要ある? とか思ったりもするし…

全文検索するなら、graphql の body とか html に対して、検索処理を行って…という感じになりそう?

記事が増えたら、処理に時間掛かりそうだなぁ…

graphql で試してみる

{
  allMarkdownRemark(filter: {frontmatter: {categories: {eq: "magical creatures"}}}) {
    edges {
      node {
        frontmatter {
          title
          categories
        }
      }
    }
  }
}

ドキュメントに上記のソースが掲載されていたので、http://localhost:8000/\_\_\_graphql で以下を試してみました。

{
  allMdx(filter: {frontmatter: {tags: {eq: "GatsbyJS"}}}) {
    edges {
      node {
        frontmatter {
          title
        }
      }
    }
  }
}

これを実行してみると

{
  "data": {
    "allMdx": {
      "edges": [
        {
          "node": {
            "frontmatter": {
              "title": "Gatsbyの記事に目次を作成してみる"
            }
          }
        },
        {
          "node": {
            "frontmatter": {
              "title": "このブログについて"
            }
          }
        },
        {
          "node": {
            "frontmatter": {
              "title": "GatsbyJSのブログに検索機能を実装してみる"
            }
          }
        }
      ]
    }
  },
  "extensions": {}
}

こんな感じで GatsbyJS というタグがついた記事のタイトルを取得出来ました。

{
  allMdx(filter: {frontmatter: {title: {eq: "GatsbyJS"}}}) {
    edges {
      node {
        frontmatter {
          title
        }
      }
    }
  }
}

次にタイトルに GatsbyJS が入っているものを取得しようとして、上記のコードを実行してみると…

{
  "data": {
    "allMdx": {
      "edges": []
    }
  },
  "extensions": {}
}

取得出来ない…

title ではなく summary に対して同様に試してみましたが、こちらも上手くいかず…

{
  //eqだと取得出来ない(inでも同じ)
  allMdx(filter: {frontmatter: {title: {eq: "GatsbyJS"}, summary: {eq: "GatsbyJS"}}}){
  //neだと取得出来る
  allMdx(filter: {frontmatter: {title: {ne: "GatsbyJS"}, summary: {ne: "GatsbyJS"}}}){
  //ninでも取得出来る
  allMdx(filter: {frontmatter: {title: {nin: "GatsbyJS"}, summary: {nin: "GatsbyJS"}}}){
    edges {
      node {
        frontmatter {
          title
        }
      }
    }
  }
}

色々試してみたら、 eq や in ではなく ne と ini を使った場合に、title と summary で値を取得出来ました。

comparator は上記のページに掲載されていますが、何故 tags の場合と同様に eq や in で取得出来ずに、 ne と nin の場合に取得出来るのかが分からず…

フォームに検索する語句が入力される度に、(graphql の)filter を使ったクエリを発行する方法は、思ったより大変そう…

別の方法を考えてみる

他の方法だと、記事内の検索されそうな語句を使って要約を用意して、それに対して検索処理を掛けたら、全文検索っぽいのが出来るんじゃない?

この方法なら全文検索より負荷は掛からなそうだし…

---
title: "GatsbyJSのブログに検索機能を実装してみる"
date: "2022-06-17T11:15:00.000Z"
summary: "GatsbyJSで作成したブログに、検索フォームを実装してみました。Algoliaの様に全文検索とまではいきませんが…"
tags: ["GatsbyJS"]
---

例えばこの記事だと、gatsbyjs、ブログ、検索フォーム、全文検索 などの語句を使って、要約を作成するという感じですね。

そんなことを考えている時に、以下のブログに行き着きました。

参考にさせて頂いた記事

今回は、diff001a さんの方法で実装してみることに!

工夫した点

MDN Web Docs の記事は、filter や indexOf の使い方が、詳しく書かれています。

(自分の場合は)Index ページに検索フォームを設置しているので、投稿された記事一覧を取得するクエリをそのまま使って、(検索用に別途クエリを作成しなくても)実装が出来ました。

検索ワードが入力されたら、キーワードに一致する記事を絞り込み、検索フォームの下に表示する様にしてみました。

検索ワードが入力されていない場合は、投稿されている全記事が表示されます。

(検索ワードを入力した場合)タイトルだけではなく記事の要約も表示されるので、(クリックせずとも、なんとなくですが)あ〜、こんな内容の記事なのね…と理解出来るかなぁと。

最後に、検索フォームにフォーカスが当たった際のアニメーションですが、特に意味はありません。

そういえばフォームに CSS の transition を適用したことないなぁ…と思っていたので、今回ちょっと試してみたまでです。