kintone のクエリ記法 (というかレコード取得) でよく起こるミス

業務で経験したこととか、聞いたこととか、調べたこととか。備忘録のために書きました。

気が向いたら追加するかも。

# 文法

### `order by` `limit` `offset` の順番間違い

kintone のクエリ記法は `条件` -> `order by` -> `limit` -> `offset` の順番に記述しないと文法エラーになります。

```js
// offset と limit が逆
const invalid1 = '文字列1行 = "" offset 100 limit 100';

// order by が一番後ろになっている
const invalid2 = 'limit 100 offset 100 order by $id desc';
```

最近は脳死で REST API Client を使うのでもはや気にしていませんが、古いコードを直すときとかは気を付けましょう。(n敗)



### `order by ～` の後に `asc` を忘れる

~~kintone では `order by` の後に `asc` / `desc` を付けないと文法エラーになります。~~

~~特に SQL に慣れている人は要注意。昇順に並び替えたい場合によく `asc` を付け忘れることがあります。(n敗)~~

~~いや、逆に SQL が省略できるのが悪い。そんなの楽したいと思っちゃうじゃないか (逆ギレ)~~

[kintone developer community で教えていただいた](https://community.cybozu.dev/t/topic/10185/4?u=wv-sumichan) のですが、どうやら `asc` を指定しなくてもエラーにならず、その場合 `desc` を指定した時と同じ挙動になるみたいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529493/e480906f-29f4-477a-9e22-5f5d23971b3f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529493/1321b780-fab1-4cc0-87e3-057aeeca3843.png)

なお `order by` 句自体を省略すると、レコード番号( `$id` )の降順になります。

また敗走回数が増えてしまいましたね……(n敗)



### エスケープをし忘れる / 過剰にしてしまう

だいたい `"` のせいなのですが、エスケープ処理どこまで書けばいいんだっけ？って迷うことが多々あります。

https://cybozu.dev/ja/kintone/docs/overview/query/#escape

例えば、文字列フィールドに `"Hello."` という文字列が含まれているかどうか、という条件のクエリを書く場合、次のようになります。

```
文字列 like "\"Hello.\""
```

問題はこれをプログラミング言語上で表現する場合。プログラミング言語側のエスケープ処理も混じってくるので、まあまあ混乱します。

```js
// シングルクオーテーションならまだ簡単
const query1 = '文字列 like "\\"Hello.\\""';

// 文字列をダブルクオーテーションで囲む規約だともう最悪
const query2 = "文字列 like \"\\\"Hello.\\\"\"";
```

JavaScript なら `'` が使えるのでまだ簡単ですが、ほかの言語だと `"` でしか文字列をリテラル化できない場合が多いので、極端に読みづらくなります。

エスケープの数を間違えるとそもそもプログラムコードとして成立しなくなるパターンもあるので、気を付けましょう。(n敗)



# フィールド・値

### `in` 句の括弧の中の要素が無い

チェックボックスやラジオボタンの検索には `in` 句を使いますが、何かしらの条件をもとに検索を掛けようとしたとき、手癖でクエリを書くと危険です。

```js
const list = [];
const invalid = `チェックボックス in (${list.map(x => `"${x}"`).join(', ')})`;
```

これ実行すると `チェックボックス in ()` になります。括弧の中に何もないのでエラーになります。(n敗)

要素数はちゃんとチェックしましょう。

どうも kViewer だとこの状態のクエリを発行する設定で保存ができちゃうみたいなので、結構メジャーな間違いかも。



### `null` や `undefined` で検索してしまう

そもそも変数の中身が空なのに、そのまま文字列に連結しちゃうこともあります。

```js
function makeQuery(search) {
  return `文字列1行 = "${search}"`;
}

const query = makeQuery();
```

これを実行すると `文字列1行 = "undefined"` になります。エラーにはなりませんがレコードは見つかりません。(n敗)

プログラム全般の話になりますが、ちゃんとぬるぽチェックをしましょう。



### 日時に `"` をつけ忘れる

実は結構な頻度でやらかします。

```js
const date = '2025-04-01';
const invalid = `日付 > ${date}`;
```

これを実行すると `日付 > 2025-04-01` になります。ダブルクオーテーションが無いのでエラーです。(n敗)

付けなくて良いのは、基本的には数値だけです。気を付けましょう。



### テーブル内フィールドに `=` を使ってしまう

特に文字列フィールドを検索するときに使ってしまうことがあります。でも使えません。(n敗)

テーブル内のフィールドの検索には `in` 句を使って、いずれかの文字列と一致するかどうかで絞り込みましょう。

https://cybozu.dev/ja/id/b05ff19d869f1609a1326dc7/#operator

そもそもの話、テーブルの中身でレコードの検索するのは結構システマチックな思考が必要になるので、設計する際は気を付けましょう。


### レコードが登録されてから `like` 検索できるようになるまでが遅い

kintone の仕様上、インデックス生成が非同期で行われているので、レコード登録されてから `like` 検索ができるようになるまで若干のタイムラグがあります。
大量のデータを CSV や REST API などで突っ込んだ時は、待ち行列が発生してかなり処理に時間がかかるようです。

実際に、私が大量 POST / DELETE のリクエストをテストしていたら、全然関連性のない日報アプリをお客さんが打つときに採番処理で `like` 検索を使っていて、他の人が打った内容が引っかかってくるまで5分くらいかかってて、採番がかぶって登録できないという事例がありました。 `=` とか `>` / `<` はレコード登録直後から動くのに… (1敗)

なお、これは 2018 年くらいに経験したことで、当時テクニカルサポートに連絡して確認した挙動です。
今はバックエンドの刷新が続いていて、多少は状況が変わっている可能性もあります。

…って書こうと思ってたら公式で載ってました。仕様っぽいですね。

https://cybozu.dev/ja/id/efa3df271da785617c8e5b38/#important-notice



# 制限

### `like` `not like` を使った検索は上限 100,000件

詳しくは [ここ](https://cybozu.dev/ja/id/ba1703e9391653c667ce958b/#get-records) に記載がありますが、上限を超えるとレスポンスヘッダーの `X-Cybozu-Warning` に `Filter aborted because of too many search results` が格納されます。

採番で最新のレコードを取ってくるときに、コードに含まれている識別子で最新を取り分ける…ということとかし始めるとこれに引っかかる可能性が出てくるので注意。(1敗)

### `offset` は上限 10,000件

たまーに古いコードで遭遇します。
いろんな人がいろんなナレッジを書いているし、公式もちゃんと記事を出しているので、気を付けましょう。

https://cybozu.dev/ja/kintone/tips/best-practices/data-acquisition-operation/kintone-get-records-with-offset-limitation/

回避方法としては、

- `$id` 順にしてどこまで取得したか記録しながら絞り込みを狭めていく
    - `$id > 0 order by $id asc` -> `$id > 500 order by $id asc` -> `$id > 1000 order by $id asc` …みたいな
- カーソル API を使う (後述)
- そもそも 10,000件 も取得する必要のない処理に置き換える

くらいですかね。



### URL にクエリを含めるときの上限はURL全体長 8KB

URLの長さが 8KB を超えると `414 Request URL Too Large` エラーになります。

例えば何かしらのキーをもとにデータを取ってくるとき、以下のようなコードを書いたとします。

```js:手癖で書くと危険です
const codes = [ 'ID-00000001', 'ID-00000002', 'ID-00000003', /* あと500件くらい */ ];
const toolong = `個人コード in (${codes.map(c => `"${c}"`).join(', ')})`;
```

1つの個人コードが 11文字 なので、ざっくり 5500文字 = 40KB くらい。もうダメです。(n敗)

こういう時はリクエストを分けるか、 POST で投げられるようにする `X-HTTP-Method-Override` を使うようにしましょう。

https://cybozu.dev/ja/id/d509b956c8f84c45e1e129ae/#request-headers



### POST の本文にクエリを含めるときの上限はボディ全体 50MB

この間知った事実なんですが、 kintone はめちゃくちゃでかいリクエストも受け付けてくれます。

https://jp.cybozu.help/k/ja/id/04044.html#limitation_limit_3040

「いくら POST にしたところで無尽蔵にリクエスト受け付けてくれるわけないよなぁ～」と思っていたそこのアナタ。逆にリクエストを分けすぎると、コール回数が増えたり時間がかかったりするので、リソース枯渇を招くことになります。(n敗)

思い切って全部いっぺんに投げることも一つの手だと思います。

とはいえクエリが 50MB もあるリクエストって、本当に必要なんでしょうか…？考慮する余地はあるでしょうね…。



### `(` / `)` を使ったグループ化は 32 個までって聞いたけど…

`and` / `or` を組み合わせるために使う `(` / `)` の上限数、どこかで 32 って見た気がするんだけど、今探しても情報が出てこないんですよね…

有識者の方がいたら教えてください。よろしくお願いいたします。



### API の同時接続数の上限は 100

これは結構有名な話なので、知っている人も多いと思います。

私は引っかかった経験がないのでわかりませんが、一覧をカスタマイズするプラグインとか使っていると API の発行タイミングを制御しづらいので、露見する恐れがあります。
また `Promise.all()` とかで同時に複数のリクエストを投げる処理を作ってしまうと、ユーザー単位でみると接続可能数は反比例で減っていきます。

https://cybozu.dev/ja/id/d509b956c8f84c45e1e129ae/#limitations-concurrency

特に初心者がよく参考にしそうな JavaScript のプログラミング講座的な記事には

> 非同期処理は `Promise.all()` を使って同時に行いましょう (絶対正義) (自己満足) (異論は認めない)

みたいな感じのことが平気で書いてあるので (偏見) 、 kintone では気を付けましょう。



### カーソルの上限は 10

前述のとおり `offset` の上限回避の手段の一つに「カーソル API を使う」というものがありますが、ドメインあたり同時に 10 カーソルしか作成できません。

https://cybozu.dev/ja/id/4e59634133e0f320b35f8711/#limitations

正直この API 、多数のユーザーが触るような場所では使えないし、ほかの `offset` 上限回避策もあるから、ほとんど使う場面が無いのかなぁと思います。
たまにバッチ処理とかで使うかな？くらいのガチ開発者向け機能だと思います。

噂によると一覧カスタマイズをするプラグインでこの API が使われてることがあるみたいな…ちゃんとドキュメント読んでるんですかね？



### 1アプリに対しての API コール数の上限は 10,000件/日

各アプリごとにコール回数が計測されていて、 kintoneシステム管理 の「アプリ管理」の画面から最新の値を確認することができます。超えてもすぐには止められませんが、ずっと続けてるとサイボウズから怒られます。

基本的には 10,000件 もあれば工夫次第で何とかなることが多いと思っています。今までほとんど超えたことは無いです。



### バルクリクエストは含まれているリクエストごとに1カウント

しっかりヘルプに記載されています。
たまに社内で質問されることがあるのですが、そもそも「複数アプリのレコード操作を一括処理する」ための API なので、含まれているリクエストごとにカウントが分かれて当然だと思います。

https://jp.cybozu.help/k/ja/id/04044.html#limitation_limit_3030

ただし、バルクリクエスト自体はコール数にカウントされないので、個別に投げたときと差が出ることはなさそうです。



# その他

### バルクリクエストはデータベースのロックを引き起こす (っぽい)

詳しい条件は分かりませんが、結構使ってると

> データベースがロックされています。時間をおいて再度お試しください

みたいなエラーが出ることがあります。(n敗)
エラーメッセージが出なくても、レコード追加画面で保存ボタンを押しても全然応答が返ってこないとかざらにあります。(n敗)

経験から察するに、複数アプリを同時に操作するバルクリクエストを行うと、全アプリのテーブルロックが発生して関係ないアプリの操作も待たされてしまうのではないかと考えています。
正しい情報ではないので鵜吞みにはしてほしくないですが、そもそも kintone に負荷を与える状況をできるだけ少なくするような運用・技術設計を心掛けたいですね。


### `totalCount: true` を付け忘れる

レコードを取得するときによく `totalCount: true` をつけ忘れて再帰処理が上手くいかない時があります。

https://cybozu.dev/ja/id/ba1703e9391653c667ce958b/#request

REST API Client を使っていたらもう何も考えないのですが、自分で再帰処理を書くときは気を付けましょう。(n敗)



### REST API で `await` し忘れる

JavaScript はもちろん他の言語でも同様ですが、非同期処理を行うときは `await` を使って結果を待つ必要があります。

一般的に外部通信は非同期処理として扱われるので、 kintone のカスタマイズを行うときも気を付ける必要があります。

```js:kintone.api を使うとき
const data = {
  app: kintone.app.getId(),
  query: '作成日時 = TODAY()',
};

const resp = kintone.api(kintone.api.url('/k/v1/records.json', true), 'GET', data);

// await していないのでエラー
console.log(resp.records.map(record => record.文字列__1行_.value));
```

```js:REST API Client を使うとき
const client = new KintoneRestAPIClient();

const data = {
  app: kintone.app.getId(),
  condition: '作成日時 = TODAY()',
};

const resp = client.record.getAllRecords(data);

// await していないのでエラー
console.log(resp.map(record => record.文字列__1行_.value));
```

期待する `resp` の中身は通信のレスポンス (つまり取得したレコード) なのですが、 JavaScript ではここは `Promise` オブジェクトになります。したがって `await` するか `Promise.prototype.then()` を使ってメソッドチェーンする必要があります。

このあたりは kintone のお勉強というよりは JavaScript とか非同期処理のお勉強になるので、ガチ開発者目線の記事を読むことをお勧めします。

ちなみに私は JavaScript の `Promise` を勉強するのに

https://postd.cc/how-do-promises-work/

の記事がとても理解の助けになったので、皆さんも一読してみてはいかがでしょうか。楽しいですよ。



# いかがでしたか？

結構頑張って書きました。

読んでて「あ～これなったことある～」とか「今書いている処理、これ気を付けてるかな…？」とか思っていただけたら、書いた甲斐があります。

あくまで私個人の主観なので、他にもよくあるミスがあったり、気になることがあった方は教えていただけると幸いです。