Gatsby blogで関連記事を取得する

June 07, 2021

programming
article cover
Image by Brandi Redd

やること

ブログでよくある「関連記事」をGatsbyで実装する。 特定のブログ記事に関連した記事を表示することで、ユーザーの直帰率を下げることにも繋がる。更に滞在時間や平均PVが上がればSEO効果のプラスも期待できる。

Gatsbyの場合はGraphqlのQueryを使って関連記事を取得する。

関連記事が複数ある場合、それぞれの記事の関連度を数値化してソートするロジックがあればベストだけど、今回はシンプルに同じタグを持つ記事を関連記事として取得する。

前提

記事は以下のようなフォーマットで、

blog.md

---
title: "blog title"
description: "blog description"
tags: ["tag1", "tag2", ...]
---

記事を表示するページでは以下のように取得しているものとして進める。

// blogPost.js

export const BlogPost = () => {
  // ...
} 

export const pageQuery = graphql`
  query BlogPost($id: String!) {
    markdownRemark(id: { eq: $id }) {
      id
      frontmatter {
        title
        description
        tags
      }
    }
  }
`

fetched a single article data

resolverを作る

特定の条件に見合う記事を取得するには、専用のresolverを定義してやればいい。Gatsbyではgatsby-node.jsの中で、createResolversというAPIを使うことで新たなresolverを定義することができる。

// gatsby-node.js

exports.createResolvers = ({ createResolvers }) => {
  const resolvers = { /* your resolver */ }
  
  createResolvers(resolvers)
}

今回の場合は以下のような記述になる。

// gatsby-node.js

exports.createResolvers = ({ createResolvers }) => {
  const resolvers = {
    MarkdownRemark: {
      relatedPosts: {
        type: ['MarkdownRemark'],
        resolve: (source, args, context, info) => {
          return context.nodeModel.runQuery({
            query: {
              filter: {
                id: {
                  ne: source.id,
                },
                frontmatter: {
                  tags: {
                    in: source.frontmatter.tags,
                  },
                },
              },
            },
            type: 'MarkdownRemark',
          })
        },
      },
    },
  }
  
  createResolvers(resolvers)
}

このresolverではmarkdownRemarkの中にrelatedPostsという新たなフィールドを作っている。relatedPostsは記事の配列なのでタイプをtype: ['MarkdownRemark'] と指定する。

resolve() の中ではMarkdownRemarkタイプのデータの中から、同じtagを持つ記事だけを取得している。 そのままだと関連元の記事自体も取得してしまうので、idで選別して除外している。

id: {
  ne: source.id,  
},

あとはQueryを更新すれば関連記事を取得することができる。

// blogPost.js

export const BlogPost = () => {
  // ...
} 

export const pageQuery = graphql`
  query BlogPost($id: String!) {
    markdownRemark(id: { eq: $id }) {
      id
      frontmatter {
        title
        description
        tags
      }
      relatedPosts {
        frontmatter {
          title
        }
      }
    }
  }
`

fetched an article data with related posts


Profile picture

元カメラマン。今はベルリンで働くWEBエンジニア。
スロバキア人の妻とドイツ猫二匹の多国籍家族。