Draft.jsのJsonデータからテキスト部分のあいまい検索をする

Draft.jsとは、Facebook(現在Meta社)が開発しているReactにリッチエディタを簡単に導入できるライブラリです。

Draft.jsはエディタに入力された文字のスタイル(太字など)も管理するため、テキストを入力するとDraft.jsではスタイルを含んだJsonを返します。

例えば、単に `テスト投稿です`とエディタに入力すると以下のようなJsonが生成されます。

```json
{
  "blocks": [
    {
      "key": "4s107",
      "data": {
      },
      "text": "テスト投稿です",
      "type": "unstyled",
      "depth": 0,
      "entity_ranges": [
      ],
      "inline_style_ranges": [
      ]
    }
  ],
  "entity_map": {
  }
}
```

この記事では、上記のようなJsonデータからテキスト部分に対して、あいまい検索するためのクエリが、普段Jsonをそれほど使わない私には、難しく、記事もなかなかで出てこなかったので、今回記事にしました。

なお、今回はJson型ではなく、JSONB型を扱っています。DBはPostgreSQLを利用しています。


## あいまい検索するSQL

今回、contentというカラムがjsonb型になっており、そのカラムに以下のデータが入っています。

```json
{
  "blocks": [
    {
      "key": "4s107",
      "data": {
      },
      "text": "テスト投稿です",
      "type": "unstyled",
      "depth": 0,
      "entity_ranges": [
      ],
      "inline_style_ranges": [
      ]
    }
  ],
  "entity_map": {
  }
}
```

SQLはこちらです。

```sql
SELECT id, content
FROM posts, JSONB_ARRAY_ELEMENTS(content->'blocks') AS block
WHERE block ->> 'text' LIKE '%投稿%'
```


## 以下補足

JSONB_ARRAY_ELEMENTSとは何かというと、、、

JSONB_ARRAY_ELEMENTSの参考：https://www.postgresql.jp/document/13/html/functions-json.html

たとえば、こんなJSONがあり、このblocksの配列を返したいときに

<details><summary>JSONの例</summary><div>

```json
{
  "blocks": [
    {
      "key": "bk52m",
      "data": {
      },
      "text": "yahoo",
      "type": "unstyled",
      "depth": 0,
      "entity_ranges": [
      ],
      "inline_style_ranges": [
      ]
    },
    {
      "key": "514td",
      "data": {
      },
      "text": "google",
      "type": "unstyled",
      "depth": 0,
      "entity_ranges": [
      ],
      "inline_style_ranges": [
      ]
    },
    {
      "key": "7kqtk",
      "data": {
      },
      "text": "edge",
      "type": "unstyled",
      "depth": 0,
      "entity_ranges": [
      ],
      "inline_style_ranges": [
      ]
    },
    {
      "key": "a1hj2",
      "data": {
      },
      "text": "safari",
      "type": "unstyled",
      "depth": 0,
      "entity_ranges": [
      ],
      "inline_style_ranges": [
      ]
    },
    {
      "key": "ehcpf",
      "data": {
      },
      "text": "https://example.com",
      "type": "unstyled",
      "depth": 0,
      "entity_ranges": [
      ],
      "inline_style_ranges": [
      ]
    }
  ],
  "entity_map": {
  }
}
```
</div></details>


```sql
SELECT id, JSONB_ARRAY_ELEMENTS(content->'blocks') as blocks
FROM posts;
```
上記のSQLでblocksの配列が返ってきます

```SQL
# SELECT id, JSONB_ARRAY_ELEMENTS(content->'blocks') as blocks
FROM posts;
                  id                  |                                                                    blocks
--------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------
 beda9f03-3131-4845-b43a-a422ce82a59d | {"key": "4s107", "data": {}, "text": "テスト投稿です", "type": "unstyled", "depth": 0, "entity_ranges": [], "inline_style_ranges": []}
 42733b11-b091-4d05-886a-af9fb942eb5b | {"key": "bk52m", "data": {}, "text": "yahoo", "type": "unstyled", "depth": 0, "entity_ranges": [], "inline_style_ranges": []}
 42733b11-b091-4d05-886a-af9fb942eb5b | {"key": "514td", "data": {}, "text": "google", "type": "unstyled", "depth": 0, "entity_ranges": [], "inline_style_ranges": []}
 42733b11-b091-4d05-886a-af9fb942eb5b | {"key": "7kqtk", "data": {}, "text": "edge", "type": "unstyled", "depth": 0, "entity_ranges": [], "inline_style_ranges": []}
 42733b11-b091-4d05-886a-af9fb942eb5b | {"key": "a1hj2", "data": {}, "text": "safari", "type": "unstyled", "depth": 0, "entity_ranges": [], "inline_style_ranges": []}
 42733b11-b091-4d05-886a-af9fb942eb5b | {"key": "ehcpf", "data": {}, "text": "https://example.com", "type": "unstyled", "depth": 0, "entity_ranges": [], "inline_style_ranges": []}
(6 rows)

```


なので、上記のblocksのうち、さらにtext部分を抽出するには、、、

```sql
=# SELECT id, JSONB_ARRAY_ELEMENTS(content->'blocks') ->> 'text' as text
FROM posts;
                  id                  |        text
--------------------------------------+---------------------
 beda9f03-3131-4845-b43a-a422ce82a59d | テスト投稿です
 42733b11-b091-4d05-886a-af9fb942eb5b | yahoo
 42733b11-b091-4d05-886a-af9fb942eb5b | google
 42733b11-b091-4d05-886a-af9fb942eb5b | edge
 42733b11-b091-4d05-886a-af9fb942eb5b | safari
 42733b11-b091-4d05-886a-af9fb942eb5b | https://example.com
(6 rows)

```

上記のようなSQLでtext部分の抽出ができます。