ClickHouse vs MongoDB for Analytics

MongoDB is a flexible operational document database; ClickHouse is a columnar analytical database. Here is where each fits—and when to use both.

JR4 min read

MongoDB and ClickHouse both handle semi-structured data and scale beyond a single machine. That overlap causes teams to ask whether they should store application events in the MongoDB cluster they already run or add ClickHouse for analytics.

The answer comes from the workload. MongoDB is designed to read and update documents that represent current application state. ClickHouse is designed to scan and aggregate large histories of facts. Neither description makes one database universally better.

Start with the job#

Workload Better default
Load a customer document by id MongoDB
Update a nested application object MongoDB
Serve transactional application reads MongoDB
Count events by property over six months ClickHouse
Compute percentiles across billions of requests ClickHouse
Power high-cardinality analytical dashboards ClickHouse

If a database must answer both sets of questions, the conflict usually appears later as unpredictable query latency, expensive indexes, or a data model compromised for two unrelated consumers.

Document storage is ideal for current state#

A MongoDB document can closely match the object an application reads and writes:

{
  "_id": "acct_42",
  "plan": "pro",
  "members": [
    { "user_id": "usr_1", "role": "owner" },
    { "user_id": "usr_2", "role": "member" }
  ],
  "settings": {
    "timezone": "America/Los_Angeles"
  }
}

That locality is valuable. The application can retrieve one account, modify a field, index common lookup paths, and use MongoDB’s aggregation pipeline for reporting that stays reasonably close to the operational model.

MongoDB is not “schemaless” in the sense that structure does not matter. Production applications still validate shapes, manage indexes, and migrate assumptions as documents evolve. Its flexibility means the database can store varied documents without a rigid relational table, not that every possible query is automatically efficient.

Columnar storage is ideal for event history#

An analytical event table behaves differently. It may contain billions of immutable rows, while a query reads only the timestamp, event name, plan, and duration:

SELECT
  JSONExtractString(json, 'plan') AS plan,
  quantile(0.95)(JSONExtractFloat(json, 'duration_ms')) AS p95
FROM events
WHERE
  event_timestamp >= now() - INTERVAL 30 DAY
  AND JSONExtractString(json, 'event') = 'report_created'
GROUP BY plan

ClickHouse stores each column together and executes analytical operations over batches of values. It avoids reading fields the query does not reference, and repeated values such as event names and plan ids compress well.

This architecture pays off for:

  • append-heavy event and log streams
  • aggregations over long time ranges
  • group-bys across many dimensions
  • dashboard queries that repeat continuously
  • ad hoc SQL that was not known when the data arrived

The tradeoff is that ClickHouse is not where we would keep the canonical mutable account document. It is the history you analyze, not necessarily the state your request handler updates.

JSON support does not erase architecture#

Both products can work with JSON, but “supports JSON” is not enough to choose a database.

Ask:

  1. Does the common query retrieve a few complete objects or scan many partial ones?
  2. Are rows updated in place, or are new facts appended?
  3. Are access paths known in advance, or will analysts ask new questions?
  4. Does the application need transactional guarantees around current state?
  5. Can analytical scans compete with customer-facing traffic?

Those answers are more predictive than the payload format.

The practical pattern is MongoDB plus ClickHouse#

Many systems use the two databases together:

  1. MongoDB remains the source of truth for accounts, projects, settings, and other mutable entities.
  2. The application emits a domain event after an important action.
  3. That event lands in ClickHouse through a queue, pipeline, or managed ingestion API.
  4. Dashboards and investigations query ClickHouse without loading the operational database.

This is deliberate duplication. Current state and analytical history have different storage needs, retention rules, and query patterns.

Avoid copying every document blindly#

An analytics store should receive purposeful facts, not a continuous dump of everything in the application database.

Prefer events such as:

  • workspace_created
  • report_completed
  • subscription_changed
  • api_request_finished

Include stable identifiers and properties needed for analysis, but exclude passwords, access tokens, payment credentials, and unnecessary personal data. Our event tracking guide covers naming, identity, and payload design.

Where GraphJSON fits#

GraphJSON is the managed analytical side of this pattern. Your application keeps its operational database—MongoDB, PostgreSQL, or anything else—and sends selected JSON events to GraphJSON. Those events become available in ClickHouse-backed visualizations and SQL notebooks without a pipeline or cluster for your team to maintain.

Try the five-minute quickstart, then use the ClickHouse JSON guide when you want to query payload fields directly.

JR

Written by JR

Founder and builder of GraphJSON.