目次

ContentfulでEntryへのLinkの数を取得する方法

本サイトはアフィリエイトプログラムを利用した広告を表示しています

Contentfulで、あるEntryへのLinkの数をどうやって取得すればいいのか分からないかもしれません。つまり、いくつかのContent Modelから参照している合計の数を取得する方法です。

Content Delivery APIには、Entriesを取得するための検索パラメータとしてlinks_to_entryというパラメータがあります。これを使っていきます。

本サイト「applis」はNext.js+Contentfulで作っていて、記事や単語、本といったコンテンツからタグを参照しています。このタグに紐づいたEntryの数を取得するのにlinks_to_entryを使っています。本サイトの実装を例に説明していきます。

著者
Hiroki Zenigami

テクニカルライター。元エンジニア。共著で「現場で使えるRuby on Rails 5」を書きました。プログラミング教室を作るのが目標です。

スポンサーリンク

動作環境

この記事の内容は、次の各バージョンで動いています。本サイトはTypeScriptで書いているので、コードの例もTypeScriptとなっています。

ライブラリバージョン
typescript4.1.5
contentful.js8.1.7

まずlinks_to_entryについてまとめます。これはContent Delivery APIでEntriesに対する検索パラメータのひとつです。ドキュメントには次のように書かれています。

あるエントリにリンクするフィールドをもつエントリを検索するには、links_to_entry という検索パラメータを用います。値にはエントリのIDを設定します。

ドキュメントのコード例そのままですが、JavaScriptの場合は次のようにして取得します。

client
  .getEntries({
    links_to_entry: '<entry_id>',
  })
  .then((response) => console.log(response.items))
  .catch(console.error)
パフォーマンス上の注意

今回の例のように、複数のContent Modelから参照しているエントリについてはlinks_to_entryは有用です。ただ、特定のContent Modelから参照しているエントリを取得するときは、links_to_entryを使わずContent Typeを指定して取得する方が、パフォーマンスが高くなります。

では実装例の方を見ていきます。本サイトのようにタグがあり、タグを参照する記事、単語、本という3つのContent Modelがあるアプリケーションを想定します。

スポンサーリンク

Content Model

それぞれ、次のような構造であると仮定します。単語と本は記事とだいたい同じ構造なので省略します。

Content ModelField NameField Type
TagNameShort Text
SlugShort Text
Content ModelField NameField Type
PostTitleShort Text
SlugShort Text
ContentLong Text
TagReference

このときの型定義は次のようになります。タグには自身を参照しているエントリの数を格納するcountも定義しています。

export type Tag = {
  name: string
  slug: string
  count: number
}

export type Post = {
  title: string
  slug: string
  content: string
  tag: Entry<Tag>
}

タグの一覧を取得する

まず、タグの一覧を取得します。パラメータの型はanyにしていますが、実際は許容する検索パラメータの型を指定します。

export async function getTags(params?: any): Promise<Entry<Tag>[]> {
  const entries = await client.getEntries<Tag>({
    content_type: 'tag',
    ...params,
  })
  return entries.items
}

タグへの参照数を取得する

次に、取得したそれぞれのタグへの参照数を取得していきます。

export async function withLinksCountToTag(
  tags: Entry<Tag>[]
): Promise<Entry<Tag>[]> {
  await Promise.all(
    tags.map(async (tag) => {
      const entries = await client.getEntries({
        links_to_entry: tag.sys.id,
      })
      tag.fields.count = entries.total
      return tag
    })
  )
  return tags
}

参照数はJSONオブジェクトのtotalプロパティに格納されているので、これを使います。また、このコード例のようにgetTagsをラップするようにして使うことで、参照数が必要ないときにgetTagsのみを使えるようになります。

参照数を取得するときの注意

上記のコード例は、タグの数が多いとパフォーマンス上の問題やAPIのRate Limitによる制限が起きる可能性があります。本サイトはタグが数個かつNext.jsのStatic Site Generationを用いているので問題ありませんが、アプリケーションの種類によって対策を取る必要があると思います。

使い方

この二つの関数を使うと、次のようにしてタグの一覧と、それぞれのタグへの参照数を取得できます。

const tags = await withTagEntriesCount(await getTags())

まとめ

あるエントリを参照する複数のContent Modelがあるとき、参照されるエントリの参照数を取得するのにlinks_to_entryを使うといいです。特定のContent Modelを対象に参照数を取得するときは、links_to_entryではなくContent Typeを指定する方がよいパフォーマンスを期待できます。

あわせて読みたい

著者
Hiroki Zenigami

テクニカルライター。元エンジニア。共著で「現場で使えるRuby on Rails 5」を書きました。プログラミング教室を作るのが目標です。

スポンサーリンク

ブログをはじめよう

技術ブログの始め方を、たくさんの画像で分かりやすく解説しました。これまでブログをやったことがない人でも、エンジニアにとって重要なブログを今日から始められます。

ブログをはじめる