Help us understand the problem. What is going on with this article?

[HeadlessCMS] contentful でエントリーを取得する色んなクエリ

contentful を触り始めてみました。
Content Delivery API を使ってエントリーを取得するクエリの記述を一部まとめてみました。

logo.png

ブログによくある以下のような記事を取得できます。

  • 記事一覧
  • カテゴリアーカイブ
  • 月別アーカイブ
  • ページネーション
  • 検索一覧

その他詳細は公式を参照してください。

準備

client には Contentful Delivery APIクライアント が入っています。

const contentful = require('contentful')

const client = contentful.createClient({
  space: '<space_id>',
  accessToken: '<content_delivery_api_key>'
});

getEntry('<entry_id>')

エントリーIDを指定して、単一のエントリーを取得します。

client.getEntry("31TNnjawUogHlfGUoMO0M2").then(entry => {
  console.log(entry.fields.title);
  console.log(entry.fields.body);
  console.log(entry.sys.createdAt);
});

このとき fields には Content type に自身で追加したフィールド(タイトル、本文など)が入っています。
sysにはシステム管理のメタデータ(id, revision, createdAtなど)が入っています。

getEntries()

全てのエントリーを取得します。
引数にオプションを指定しない場合には、 entries.items に、記事や人やカテゴリなど、Content type を元にした全てのエントリーが配列で入ります。

client.getEntries().then(entries => {
  console.log(entries.items[0].fields.title);
  console.log(entries.items[1].fields.title);
  console.log(entries.items[2].fields.title);
});

この getEntries() の引数に様々なオプションを含めることができます。

指定した Content type の全てのエントリーを取得

以下はブログ記事の一覧を取得します。

client.getEntries({
  content_type: "blogPost"
}).then(entries => {
  console.log(entries.items); // blogPostのエントリー配列
});

指定したフィールドと一致する全てのエントリーを取得

Memoフィールドに 'hoge' という String を設定している全てのエントリーを取得します。
このように fields を使用した検索をする場合は、 content_type を指定する必要があります。

client.getEntries({
  content_type: "blogPost",
  "fields.memo": "hoge"
}).then(entries => {
  console.log(entries.items);
});

指定したフィールドと一致しない全てのエントリーを取得

[ne]オペレーターを使うと、 'hoge' という String設定していない全てのエントリーを取得します。

client.getEntries({
  content_type: "blogPost",
  "fields.memo[ne]": "hoge"
}).then(entries => {
  console.log(entries.items);
});

List形式のフィールドの検索

Likesフィールド(List形式)に 'banana' が含まれている全てのエントリーを取得します。

client.getEntries({
  content_type: "blogPost",
  "fields.likes": "banana"
}).then(entries => {
  console.log(entries.items);
});

その他のに使えるオペレータはこちら。

オペレータ
[ne] 指定した値が含まれない全てのエントリーを取得
[all] 指定した複数のパラメータが全て含まれている全てのエントリーを取得
[in] 指定した複数のパラメータのどれかが含まれている全てのエントリーを取得
[nin] 指定した複数のパラメータのどれも含まれている全てのエントリーを取得
[exists] フィールドに値が設定されている全てのエントリーを取得(パラメータがtrueの場合)
[exists] フィールドに値が設定されていない全てのエントリーを取得(パラメータがfalseの場合)

日付形式, 数値形式の検索

以下のような範囲を指定するオペレータが使用できます。

オペレータ
[lt] より小さい
[lte] 以下
[gt] より大きい
[gte] 以上

2019年10月のアーカイブスを表示したい場合、以下のようなクエリで取得します。

const year = 2019;
const month = 10;

// 年と月からその月の最終日を返す関数
const getLastDay = (year, month) => {
  const lastDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
  const isLeap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);

  if (isLeap && month === 2) {
    return 29;
  } else {
    return lastDays[month - 1];
  }
};

client.getEntries({
  content_type: "blogPost",
  "fields.publishDate[gte]": `${year}-${month}-01`, // その月の初めの日以上
  "fields.publishDate[lte]": `${year}-${month}-${getLastDay(year, month)}` // その月の最終日以内
}).then(entries => {
  console.log(entries.items);
});

全文検索

指定した文字列を含む全てのエントリーを取得できます。

client.getEntries({
  content_type: "blogPost",
  query: "orange"
})
.then(entries => {
  console.log(entries.items);
});

[match]オペレータでフィールドを指定した全文検索も可能です。

client.getEntries({
  content_type: "blogPost",
  "fields.description[match]": "Hello"
})
.then(entries => {
  console.log(entries.items);
});

エントリーの並び替え

orderを使用して、順序を指定できます。
このとき指定パラメータの接頭に - を付けると逆順になります。

client.getEntries({
  content_type: "blogPost",
  order: "-sys.createdAt"
})
.then(entries => {
  console.log(entries.items);
});

指定できるパラメータは、日付や数値やブール値、256字以下の文字列のみです。
複数指定することも可能です。

client.getEntries({
  order: '-sys.createdAt,sys.id'
})

ページネーション(取得数制限とオフセット機能)

limitを使用して、取得数を制限できます。
skip で取得位置のオフセットを指定できます。

ページネーションは以下のようなクエリで実装できます。

const MAX_ENTRY = 20;
const page = 3;

client.getEntries({
  content_type: "blogPost",
  order: "sys.createdAt",
  limit: MAX_ENTRY,
  skip: MAX_ENTRY * (page - 1)
})
.then(entries => {
  console.log(entries.items);
});

Reference形式の検索

以下は、参照形式であるcategoryフィールドを指定した検索です。
指定する Reference の content type ID もクエリに含める必要があります。

client.getEntries({
  content_type: "blogPost",
  "fields.category.sys.contentType.sys.id": "tag", // ←これも必要
  "fields.category.fields.name": "Game"
})
.then(entries => {
  console.log(entries.items);
});

[追記]
sys.id を直接指定する場合は contentTypeIDの指定はいらないっぽい。
この場合、リスト形式のReference(= Many references)での取得が可能。
指定する sys.id は contentful CMSサイト の contentページ-> 各contentページ -> 右上のInfoボタン -> ENTRY ID で確認できるランダムな英数字。

client.getEntries({
  content_type: "blogPost",
  "fields.categories.sys.id": "<ENTRY ID>"
})
.then(entries => {
  console.log(entries.items);
});

上記は複数カテゴリ(単カテゴリでも可)を持つ記事を、カテゴリ検索する場合。 事前にカテゴリを getEntries して fields の内容と一緒に sys.id を取得した上でカテゴリ検索する必要がある。

おわり

自分のサイトは何年もwordpressで運用してるので、 contentful に乗り換えてみようかと思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした