We value your privacy

This site uses cookies to improve your browsing experience, analyze site traffic, and show personalized content. See our Privacy Policy.

  1. MooseStack
  2. Engines
  3. CollapsingMergeTree

CollapsingMergeTree

CollapsingMergeTree is a MergeTree-family engine that collapses pairs of rows during background merges using a required sign column (where 1 is a “state” row and -1 is a “cancel” row). The merge behavior is defined by ClickHouse.

When to Use

  • Track object state changes without running ClickHouse UPDATEs
  • Model “current state” from a stream of changes (append-only writes)
  • Reduce storage by collapsing old states during merges

Usage

CollapsingTable.ts
import { Key, OlapTable, ClickHouseEngines, Int8 } from "@514labs/moose-lib"; interface UserActivity {  userId: Key<string>;  pageViews: number;  duration: number;  sign: Int8; // Required: 1 = state row, -1 = cancel row} const userActivity = new OlapTable<UserActivity>("user_activity", {  engine: ClickHouseEngines.CollapsingMergeTree,  sign: "sign",  orderByFields: ["userId"],});

Configuration Options

OptionTypeDescription
orderByFieldsstring[]Sorting key used by ClickHouse for grouping rows
signstringName of the Int8 sign column (1 = state, -1 = cancel)

Example: Modeling State Changes

To update an object, write two rows:

  1. A cancel row (sign = -1) that matches the prior state’s sorting key
  2. A state row (sign = 1) with the new state

Collapsing Behavior

By default, collapsing happens during ClickHouse background merges. To return fully-collapsed results, ClickHouse documents two common approaches:

  • Aggregate with sign (recommended for analytics queries)
  • Use FINAL at read time (less efficient; typically avoid on large scans)
import { sql } from "@514labs/moose-lib"; // Example: compute fully-collapsed metrics via sign-aware aggregationconst collapsed = sql`  SELECT    userId,    sum(pageViews * sign) AS pageViews,    sum(duration * sign)  AS duration  FROM user_activity  GROUP BY userId  HAVING sum(sign) > 0`;
ClickHouse behavior

For full details (including the required Sign column, algorithm, and FINAL semantics), see the ClickHouse docs: CollapsingMergeTree table engine.

See Also

  • VersionedCollapsingMergeTree — Collapsing with an explicit version column
  • MergeTree — Append-only baseline engine
  • Replicated Engines — High availability variants

On this page

When to UseUsageConfiguration OptionsExample: Modeling State ChangesCollapsing BehaviorSee Also
FiveonefourFiveonefour
Fiveonefour Docs
MooseStackHostingTemplatesGuides
Release Notes
Source531
  • Overview
Build a New App
  • 5 Minute Quickstart
  • Browse Templates
  • Existing ClickHouse
Add to Existing App
  • Next.js
  • Fastify
Fundamentals
  • Moose Runtime
  • MooseDev MCP
  • Language Server
  • Data Modeling
Moose Modules
  • Moose OLAP
  • Moose Streaming
  • Moose Workflows
  • Moose APIs & Web Apps
Deployment & Lifecycle
  • Moose Dev
  • Moose Migrate
  • Moose Deploy
Reference
  • API Reference
  • Data Types
  • Table Engines
  • CLI
  • Configuration
  • Observability Metrics
  • Help
  • Release Notes
Contribution
  • Documentation
  • Framework
CollapsingTable.ts
import { Key, OlapTable, ClickHouseEngines, Int8 } from "@514labs/moose-lib"; interface UserActivity {  userId: Key<string>;  pageViews: number;  duration: number;  sign: Int8; // Required: 1 = state row, -1 = cancel row} const userActivity = new OlapTable<UserActivity>("user_activity", {  engine: ClickHouseEngines.CollapsingMergeTree,  sign: "sign",  orderByFields: ["userId"],});
import { sql } from "@514labs/moose-lib"; // Example: compute fully-collapsed metrics via sign-aware aggregationconst collapsed = sql`  SELECT    userId,    sum(pageViews * sign) AS pageViews,    sum(duration * sign)  AS duration  FROM user_activity  GROUP BY userId  HAVING sum(sign) > 0`;