工程资源 / 什么是 JSON 数据库?

什么是 JSON 数据库?

实际上并没有所谓的 JSON(JavaScript 对象表示法)数据库,但有些数据库的设计旨在与 JSON 数据良好配合,或具有强大的 JSON 支持。

JSON 是一种基于文本的数据交换格式,在过去十年中已成为数据输出的通用语言——API 返回 JSON,它用于表示单页应用程序中的状态,并且指标或日志通常以这种格式生成。

什么是 JSON?

JSON 是一种轻量级数据交换格式,易于人类阅读和编写,也易于机器解析和生成。JSON 最初由 Douglas Crockford 在 2000 年代初期指定,其符号源自 JavaScript,迅速普及成为一种与语言无关的格式。到 2000 年代后期,它已成为传输应用程序状态和促进客户端-服务器交互的事实标准。

JSON 文档包含键/值对,其中键是字符串,值可以是字符串、整数、布尔值、数组或对象。下面显示了一个 JSON 文档示例,表示电子商务网站上的订单

{
  "orderId": "ORD-12345",
  "orderDate": "2023-05-15T14:30:00Z",
  "customer": {
    "id": "CUST-789",
    "name": "Alice Johnson",
    "email": "[email protected]"
  },
  "items": [
    {
      "productId": "BOOK-001",
      "title": "The Great Gatsby",
      "price": 12.99,
      "quantity": 1
    },
    {
      "productId": "BOOK-002",
      "title": "To Kill a Mockingbird",
      "price": 14.99,
      "quantity": 2
    }
  ],
  "totalAmount": 42.97,
  "status": "processing"
}

JSON 文档没有模式,这意味着我们可能有另一个文档表示具有略微不同字段的订单。例如,也许我们没有客户的姓名,因此 customer.name 字段将缺失。

JSON 的半结构化特性提供了灵活性,使得修改和扩展数据结构变得容易,而无需更改现有记录。它还支持快速原型设计和敏捷开发。

JSON 数据库示例

现在我们已经了解了 JSON,让我们探讨如何以这种格式存储数据。几种不同类型的数据库可以存储和检索 JSON 格式的数据。在本节中,我们将更多地了解这些数据库。

文档数据库

文档数据库(如 CouchDB 和 MongoDB)在 2000 年代末/2010 年代初兴起。这些数据库以类似 JSON 的文档形式存储数据,从而实现灵活的、无模式的数据建模。它们的主要卖点是用户可以轻松存储 JSON 并检索单个文档。

这使得它们非常适合在交互式、JavaScript 繁重的网页中存储应用程序状态,这些网页随着 jQuery 以及后来的 AngularJSReact 的出现而流行起来。像 Twitter 这样的社交媒体网站在同一时期也开始流行,并提供 JSON API 来访问其数据,用户随后将其存储在他们选择的文档数据库中。

尽管 MongoDB 和 CouchDB 是此类别中的早期竞争者,但其他还包括 Couchbase、CosmosDB 和 Firestore。

具有 JSON 支持的关系型数据库

两个最流行的开源关系型数据库 PostgreSQL 和 MySQL 最初没有 JSON 支持,它们花了一段时间才赶上。

PostgreSQL 在 9.2 版本(2012 年 9 月发布)中添加了对 JSON 的原生支持。随后,他们在后续版本中添加了对索引的支持。MySQL 也紧随其后,在 5.7.8 版本(2015 年 8 月发布)中添加了自己的 JSON 数据类型。

这些数据库仍然主要用于以行和列的形式存储数据,并检索单个或少量行。JSON 类型允许它们存储半结构化数据,但它们在处理 JSON 方面没有文档数据库那么多功能。

具有 JSON 支持的实时分析数据库

在 2010 年代后期和 2020 年代初期,出现了实时分析数据库,如 Apache Druid、Apache Pinot、Rockset 和 ClickHouse。这些数据库使用基于列的存储,并专注于优化跨数十亿行或更多行的大规模分析查询。

它们都具有从 JSON 文档中提取模式的功能,如果所有 JSON 文档都具有相同的模式,则效果良好。

然而,对于常见的用例(如可观测性和日志记录),数据通常是半结构化的,这意味着这些数据库也必须添加对 JSON 数据类型的支持。

在存储数据时,它们需要确保以允许快速执行嵌套 JSON 查询的方式存储数据——将数据存储为字符串并将工作推迟到查询时间是不够好的。

ClickHouse 中的 JSON

ClickHouse 在 2022 年 6 月的 22.6 版本中添加了 JSON 数据类型,但此实现存在一些限制,并在 24.8 版本(2024 年 8 月发布)中被新的 JSON 数据类型取代。

新的数据类型解决了以下挑战

  1. 真正的列式存储 - 为 JSON 数据实现列式存储系统,以实现高效的压缩和快速的向量化操作。
  2. 动态更改数据而无需类型统一 - 处理具有不同数据类型的 JSON 路径,而无需将它们统一为通用类型。
  3. 防止磁盘上出现大量列数据文件 - 避免为唯一的 JSON 路径在磁盘上创建过多的列文件。
  4. 密集存储 - 以密集、非冗余的方式存储唯一 JSON 路径的值。

目前这是一个实验性功能,因此您需要启用以下标志才能使用它

SET allow_experimental_json_type = 1;

完成后,您可以创建一个包含一个或多个 JSON 类型字段的表。我们将从 StatsBomb 开放数据集导入一个包含足球/足球赛事的 JSON 文件 (StatsBomb open dataset)。它只包含几千个事件,但这足以了解 JSON 类型的工作原理。

我们将创建以下表

CREATE TABLE events
(
    matchId String,
    json JSON,
    possession_team_id String MATERIALIZED getSubcolumn(
      json, 'possession_team.id')
)
ENGINE = MergeTree
ORDER BY possession_team_id;

然后导入数据

INSERT INTO events
SELECT15946AS matchId,
    json
FROM url(
  'https://raw.githubusercontent.com/statsbomb/open-data/refs/heads/master/data/events/15946.json', 
  JSONAsObject
);

然后我们可以编写以下查询来查找最常见的事件类型

SELECT
    json.type.name,
    count()
FROM events
GROUP BY ALL
ORDER BY count() DESC
LIMIT 10;

┌─json.type.name─┬─count()─┐
│ Pass           │    1163 │
│ Ball Receipt*1058 │
│ Carry          │     890 │
│ Pressure       │     212 │
│ Ball Recovery  │      89 │
│ Duel           │      53 │
│ Clearance      │      37 │
│ Goal Keeper    │      34 │
│ Block          │      32 │
│ Shot           │      28 │
└────────────────┴─────────┘

常见问题

让我们回顾一些关于在数据库中存储 JSON 的常见问题。

哪个数据库最适合 JSON?

这取决于您在 JSON 数据进入数据库后如何处理它!如果您正在检索单个文档,则像 MongoDB 或 Couchbase 这样的数据库可能是最佳选择。如果您要对许多 JSON 文档运行分析查询,则 ClickHouse 可能是更好的选择。

JSON 是 SQL 还是 NoSQL?

您可以将 JSON 数据存储在 NoSQL 和 SQL 数据库中。可以存储 JSON 的 NoSQL 数据库示例包括 MongoDB 和 Couchbase。可以存储 JSON 的 SQL 数据库示例包括 PostgreSQL 和 ClickHouse。

可以使用 SQL 查询 JSON 吗?

是的,ClickHouse 允许您使用 SQL 查询 JSON 数据。例如,假设我们有这样的 JSON 文档

{
    "duration": 0,
    "id": "9f6e2ecf-6685-45df-a62e-c2db3090f6c1",
    "index": "1",
    "minute": "0",
    "period": "1",
    "play_pattern": {"id": "1", "name": "Regular Play"},
    "possession": "1",
    "possession_team": {"id": "217", "name": "Barcelona"},
    "second": "0",
    "tactics": {"formation": "442", "lineup": []},
    "team": {"id": "217", "name": "Barcelona" },
    "timestamp": "00:00:00.000",
    "type": {"id": "35", "name": "Starting XI"}
}

我们可以将此数据存储在名为 events 的表中,模式如下

┌─name───────────────┬─type───┐
│ matchId            │ String │
│ json               │ JSON   │
│ possession_team_id │ String │
└────────────────────┴────────┘

然后我们可以编写以下查询来查找最受欢迎的事件类型

SELECT json.type.name, count() AS count 
FROM events 
GROUP BY ALL 
ORDER BY count DESC 
LIMIT 10;
分享此资源
关注我们
X imageSlack imageGitHub image
Telegram imageMeetup imageRss image
©2025ClickHouse, Inc. 总部位于加利福尼亚州湾区和荷兰阿姆斯特丹。