You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

实时协作编辑器数据库存储机制及支持Operational Transform/CRDT的Schema设计咨询

Hey there! Let me break down these two key questions based on my experience building real-time collaborative editors and digging into industry best practices.

1. How to Store Collaborative Editor Documents in a Database

There are three primary storage patterns used in real-time editors, each with tradeoffs for performance, complexity, and use case:

  • Full Snapshot + Operation Logs
    This is the most common approach for OT-based systems. You store a full, serialized snapshot of the document (e.g., as JSON, Protobuf, or plain text) for quick initial loading, plus a detailed log of every edit operation. The snapshot lets new clients load the document instantly, while the operation log is used to replay edits, resolve conflicts via OT, and sync with offline clients.

  • Lazy Snapshotting (Operation Logs First)
    For large documents with frequent edits, storing only operation logs initially can save space. You generate snapshots periodically (e.g., every 100 operations or hourly) to avoid long initial load times. This balances storage efficiency with usability—clients load the latest snapshot, then apply any subsequent operations to catch up.

  • CRDT-Based Direct Storage
    If you’re using CRDTs, you can directly store the serialized CRDT state (e.g., Yjs’s YDoc or Automerge’s document) in the database. CRDTs are designed for eventual consistency, so you don’t need to track strict operation sequences. You can either store the full state each time or incremental deltas (partial changes) to reduce bandwidth and storage overhead.

2. Database Schema for OT or CRDT Support

The schema depends heavily on whether you’re using OT or CRDTs—here’s what each looks like in practice:

For Operational Transform (OT)

OT relies on strict version control and ordered operation sequences, so your schema needs to enforce this:

Document Metadata Table

Tracks core document info and current state to avoid replaying all operations on every load:

CREATE TABLE documents (
    id UUID PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    current_version INT NOT NULL DEFAULT 0,
    latest_snapshot JSONB, -- Use JSON for non-PostgreSQL databases
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

Operations Log Table

Stores every edit operation, tied to a specific document version to enable OT conflict resolution:

CREATE TABLE ot_operations (
    id UUID PRIMARY KEY,
    document_id UUID REFERENCES documents(id) ON DELETE CASCADE,
    user_id UUID NOT NULL,
    operation_type VARCHAR(50) NOT NULL, -- e.g., 'insert', 'delete', 'format'
    operation_data JSONB NOT NULL, -- e.g., {"position": 10, "text": "hello", "length": 5}
    base_version INT NOT NULL, -- The document version this operation was intended for
    applied_version INT NOT NULL, -- The version after applying this operation
    timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(document_id, base_version) -- Prevent duplicate operations for the same version
);

Key note: The base_version and applied_version fields are critical for OT—when a client submits an operation, the server checks if the base version matches the current document version. If not, the server transforms the operation to fit the current state before applying it.

For Conflict-free Replicated Data Types (CRDT)

CRDTs don’t require strict ordering, so the schema is simpler and more flexible:

Basic CRDT Document Table

Stores the serialized CRDT state directly—most CRDT libraries provide built-in serialization for this:

CREATE TABLE crdt_documents (
    id UUID PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    crdt_state BYTEA, -- Use binary for compact storage (e.g., Yjs's Uint8Array)
    -- Or JSONB for JSON-based CRDTs: crdt_state JSONB,
    version BIGINT NOT NULL DEFAULT 0, -- Optional, for tracking update count
    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

Optional CRDT Delta History Table

If you need to track edit history or support incremental sync, store partial changes (deltas) instead of full state updates:

CREATE TABLE crdt_deltas (
    id UUID PRIMARY KEY,
    document_id UUID REFERENCES crdt_documents(id) ON DELETE CASCADE,
    user_id UUID NOT NULL,
    delta BYTEA NOT NULL, -- Incremental CRDT change
    timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    sequence_number BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY -- Preserves delta order
);

Key note: For CRDTs, you can choose between full state storage (easier to implement) or delta storage (better for bandwidth and large documents). Many libraries handle delta merging automatically, so you don’t need to manage conflict resolution in the database.

Quick Practice Tips
  • Database Selection: OT works best with relational databases (PostgreSQL, MySQL) that support transactions and strong consistency. CRDTs are flexible—you can use relational databases, document databases (MongoDB), or even distributed databases (CockroachDB) depending on your scaling needs.
  • Performance: For OT, periodically merge old operations into a new snapshot to keep log sizes manageable. For CRDTs, use binary serialization instead of JSON to save space and speed up serialization/deserialization.

内容的提问来源于stack exchange,提问作者Ajeet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 11:49:04