入門記事単語書籍

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

読者のイメージ

Contentfulで、あるEntryへのLinkの数はどうやって取得すればいいの? いくつかのContent Modelから参照している合計の数を取得したいな。

という悩みに回答していきます。

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

本サイト『Product Development IO』はNext.js+Contentfulで作っていて、記事や単語、本といったコンテンツからタグを参照しています。このタグに紐づいたEntryの数を取得するのに links_to_entry を使っています。

本サイトの実装を例に説明していきますね。

動作環境

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

ライブラリバージョン
typescript4.1.5
contentful.js8.1.7
読者のイメージ

links_to_entry を使えばいいことはわかったけど、そもそも links_to_entry ってなんだろう?

まず 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を指定する方がよいパフォーマンスを期待できます。

技術ブログを書く・読むのが好き🧑‍💻 Webエンジニア←プログラミング教育で起業←東大院←熊本高専。

Follow @zenizh
\ 記事をシェアしよう /

この記事を気に入っていただけましたら、ぜひフォロワーの方にシェアしてくださいね

ツイート画面をひらく
関連記事関連書籍
現場で使えるRuby on Rails 5

共著で『現場で使えるRuby on Rails 5(マイナビ出版)』を書きました。

Amazonでみる
Product Development IO
ゼロからWebエンジニアになるためのブログ
お問い合わせ
ご意見・ご質問やお仕事のご依頼などは下記よりお願いいたします
お問い合わせ
© Product Development IO