Contentfulで、あるEntryへのLinkの数をどうやって取得すればいいのか分からないかもしれません。つまり、いくつかのContent Modelから参照している合計の数を取得する方法です。
Content Delivery APIには、Entriesを取得するための検索パラメータとしてlinks_to_entryというパラメータがあります。これを使っていきます。
本サイト「applis」はNext.js+Contentfulで作っていて、記事や単語、本といったコンテンツからタグを参照しています。このタグに紐づいたEntryの数を取得するのにlinks_to_entry
を使っています。本サイトの実装を例に説明していきます。
テクニカルライター。元エンジニア。共著で「現場で使えるRuby on Rails 5」を書きました。プログラミング教室を作るのが目標です。
動作環境
この記事の内容は、次の各バージョンで動いています。本サイトはTypeScriptで書いているので、コードの例もTypeScriptとなっています。
ライブラリ | バージョン |
---|---|
typescript | 4.1.5 |
contentful.js | 8.1.7 |
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を指定して取得する方が、パフォーマンスが高くなります。
links_to_entryの実装例
では実装例の方を見ていきます。本サイトのようにタグがあり、タグを参照する記事、単語、本という3つのContent Modelがあるアプリケーションを想定します。
Content Model
それぞれ、次のような構造であると仮定します。単語と本は記事とだいたい同じ構造なので省略します。
Content Model | Field Name | Field Type |
---|---|---|
Tag | Name | Short Text |
Slug | Short Text |
Content Model | Field Name | Field Type |
---|---|---|
Post | Title | Short Text |
Slug | Short Text | |
Content | Long Text | |
Tag | Reference |
このときの型定義は次のようになります。タグには自身を参照しているエントリの数を格納する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を指定する方がよいパフォーマンスを期待できます。