migration
Migrate data and schemas to Couchbase from relational databases (PostgreSQL, MySQL), MongoDB, or DynamoDB
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Migrate data and schemas to Couchbase from relational databases (PostgreSQL, MySQL), MongoDB, or DynamoDB
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Couchbase SDK error handling — UnambiguousTimeoutException vs AmbiguousTimeoutException, DocumentNotFoundException, CasMismatchException, DurabilityImpossibleException, SDK debug logging, sdk-doctor connectivity diagnostics, retryable vs non-retryable errors, circuit breaker, error best practices
Couchbase SDK patterns for Rust — CAS optimistic locking, retry on CasMismatch, tokio bulk operations with join_all/FuturesUnordered, atomic counters, sub-document (MutateInSpec/LookupInSpec), array operations, exists, replica reads, touch/getAndTouch, preserve_expiry, error handling
Configure and optimize Couchbase SDK connections in Rust — async/tokio cluster setup, singleton pattern, wait_until_ready, timeouts, KV CRUD (upsert/insert/get/replace/remove), expiry, durability, sub-document operations
SQL++ queries with the Couchbase Rust SDK — scope.query, cluster.query, positional and named parameters, scan consistency, deserializing rows into structs, DML (INSERT/UPDATE/DELETE/UPSERT), MutationState RYOW
Testing Couchbase Rust applications — unit testing with mockall, integration testing with testcontainers-rs, scope/collection isolation
Distributed ACID transactions are not supported by the Couchbase Rust SDK 1.x — alternatives and workarounds
| name | migration |
| summary | Migrate data and schemas to Couchbase from relational databases (PostgreSQL, MySQL), MongoDB, or DynamoDB |
| description | Migrate data and schemas to Couchbase from relational databases (PostgreSQL, MySQL), MongoDB, or DynamoDB |
| allowed-tools | Bash |
| compatibility | cbimport/cbexport are included with Couchbase Server. cbsh can be used as an alternative for imports. No live cluster required for schema translation. |
| metadata | {"last_verified":"2026-05","min_server_version":"7.0","handoff":[{"condition":"user asks about data modeling decisions","skill":"server-data-modeling"},{"condition":"user asks about slow queries or index recommendations","skill":"server-query-optimizer"},{"condition":"user asks about SQL++ queries","type":"variant","skill":"server-querying-python"},{"condition":"user asks about Couchbase fundamentals or core concepts","skill":"getting-started"}]} |
cbimport json is the primary tool for loading JSON data into Couchbase.
| Format | Description | Flag |
|---|---|---|
lines | One JSON document per line (JSONL/NDJSON) | --format lines |
list | A JSON array of documents | --format list |
sample | Couchbase sample bucket ZIP | --format sample |
# Lines format (JSONL) — most common for large datasets
cbimport json \
-c couchbase://localhost -u Administrator -p "$CB_ADMIN_PASSWORD" \
-b myapp \
--scope-collection-exp "_default.orders" \
-d file:///data/orders.jsonl \
--format lines \
--generate-key "%id%" \
--threads 4 \
--errors-log /tmp/import-errors.log
# List format (JSON array)
cbimport json \
-c couchbase://localhost -u Administrator -p "$CB_ADMIN_PASSWORD" \
-b myapp \
--scope-collection-exp "_default.products" \
-d file:///data/products.json \
--format list \
--generate-key "product::%sku%" \
--threads 4
# From a document field
--generate-key "%id%"
# Composite key from multiple fields
--generate-key "order::%customerId%::%orderId%"
# With auto-increment (when no natural key exists)
--generate-key "doc::#MONO_INCR#"
# With UUID
--generate-key "#UUID#"
# Nested field
--generate-key "%address.country%::%id%"
# Static scope.collection
--scope-collection-exp "orders.history"
# Dynamic — from document fields
--scope-collection-exp "%type%.%subtype%"
# e.g. doc {"type":"orders","subtype":"2024"} → orders.2024 collection
cbimport json \
-c couchbases://cb.xxxxx.cloud.couchbase.com \
-u db-user -p db-password \
--no-ssl-verify \
-b myapp \
--scope-collection-exp "_default.orders" \
-d file:///data/orders.jsonl \
--format lines \
--generate-key "%id%"
# cbsh import — simpler syntax, same result
cbsh --script "
cb-env bucket myapp
doc import /data/orders.jsonl --scope _default --collection orders --id-field id
"
# Export a collection to JSONL
cbexport json \
-c couchbase://localhost -u Administrator -p "$CB_ADMIN_PASSWORD" \
-b myapp \
--scope-collection-exp "_default.orders" \
-o /data/orders-export.jsonl \
--format lines \
--threads 4
# Export with a SQL++ filter (via cbq, not cbexport)
cbq -e couchbase://localhost -u Administrator -p "$CB_ADMIN_PASSWORD" \
--script "SELECT * FROM \`myapp\`._default.orders WHERE status = 'completed'" \
| jq -c '.results[]' > /data/completed-orders.jsonl
Core rule: denormalize tables that are always JOINed together into a single document. Keep tables that are accessed independently as separate collections.
-- PostgreSQL: 3 tables always joined
SELECT o.id, o.created_at, c.name, c.email, oi.sku, oi.qty, oi.price
FROM orders o
JOIN customers c ON o.customer_id = c.id
JOIN order_items oi ON oi.order_id = o.id
WHERE o.id = 1001;
// Couchbase: 1 document (orders collection)
{
"type": "order",
"orderId": "order::1001",
"createdAt": "2024-03-15T10:30:00Z",
"customer": {
"id": "customer::42",
"name": "Alice Smith",
"email": "alice@example.com"
},
"items": [
{ "sku": "WIDGET-42", "qty": 2, "price": 9.99 },
{ "sku": "GADGET-7", "qty": 1, "price": 24.99 }
],
"total": 44.97
}
Migration script (PostgreSQL → JSONL):
psql -U postgres -d mydb -c "
COPY (
SELECT json_build_object(
'type', 'order',
'orderId', 'order::' || o.id,
'createdAt', o.created_at,
'customer', json_build_object('id', 'customer::' || c.id, 'name', c.name, 'email', c.email),
'items', (
SELECT json_agg(json_build_object('sku', oi.sku, 'qty', oi.qty, 'price', oi.price))
FROM order_items oi WHERE oi.order_id = o.id
),
'total', o.total
)
FROM orders o JOIN customers c ON o.customer_id = c.id
) TO '/tmp/orders.jsonl';
" && cbimport json -c couchbase://localhost -u Administrator -p "$CB_ADMIN_PASSWORD" \
-b myapp --scope-collection-exp "_default.orders" \
-d file:///tmp/orders.jsonl --format lines --generate-key "%orderId%"
MySQL migration follows the same denormalization pattern as PostgreSQL. Use mysqldump or a SELECT INTO OUTFILE to export, then transform to JSONL.
# Export joined tables to JSONL using MySQL's JSON functions
mysql -u root -p mydb -e "
SELECT JSON_OBJECT(
'type', 'order',
'orderId', CONCAT('order::', o.id),
'createdAt', DATE_FORMAT(o.created_at, '%Y-%m-%dT%H:%i:%sZ'),
'customer', JSON_OBJECT('id', CONCAT('customer::', c.id), 'name', c.name, 'email', c.email),
'items', (
SELECT JSON_ARRAYAGG(JSON_OBJECT('sku', oi.sku, 'qty', oi.qty, 'price', oi.price))
FROM order_items oi WHERE oi.order_id = o.id
),
'total', o.total
)
FROM orders o JOIN customers c ON o.customer_id = c.id
INTO OUTFILE '/tmp/orders.jsonl'
LINES TERMINATED BY '\n';
" && cbimport json -c couchbase://localhost -u Administrator -p "$CB_ADMIN_PASSWORD" \
-b myapp --scope-collection-exp "_default.orders" \
-d file:///tmp/orders.jsonl --format lines --generate-key "%orderId%"
If INTO OUTFILE is restricted, use mysql ... | python3 to stream:
mysql -u root -p mydb --batch --silent -e "
SELECT JSON_OBJECT('type','order','orderId',CONCAT('order::',o.id),'total',o.total)
FROM orders o
" > /tmp/orders.jsonl
MySQL → Couchbase concept mapping:
| MySQL | Couchbase |
|---|---|
| Database / Schema | Bucket |
| Table | Collection (within a scope) |
| Row | Document |
| Primary key | Document key (META().id) |
| Foreign key | Embedded document or reference by key |
AUTO_INCREMENT | NEXT VALUE FOR sequence or UUID |
| Index | GSI index |
JOIN | SQL++ JOIN or denormalized embed |
| Stored procedure | Eventing Function or application logic |
| Triggers | Eventing Function (OnUpdate / OnDelete) |
| Replication (binlog) | DCP / Kafka connector |
MySQL-specific SQL → SQL++ differences:
LIMIT x OFFSET y → same syntax works, but use keyset pagination for large offsetsGROUP_CONCAT(...) → ARRAY_AGG(...) or ARRAY_TO_STRING(ARRAY_AGG(...), ",")IFNULL(x, y) → IFNULL(x, y) (same) or NVL(x, y)NOW() → NOW_STR() (returns ISO 8601 string) or NOW_MILLIS() (epoch ms)ENUM columns → store as string; validate in application or EventingMongoDB documents map almost directly — the main differences are _id → document key and ObjectId → string.
# Export from MongoDB
mongoexport --db mydb --collection orders --out /tmp/orders.jsonl --jsonArray=false
# Transform _id ObjectId to string key
# (jq strips _id and uses its $oid value as the key field)
jq -c '{id: ._id."$oid"} + del(._id) | . + {id: .id}' /tmp/orders.jsonl > /tmp/orders-cb.jsonl
# Import to Couchbase
cbimport json -c couchbase://localhost -u Administrator -p "$CB_ADMIN_PASSWORD" \
-b myapp --scope-collection-exp "_default.orders" \
-d file:///tmp/orders-cb.jsonl --format lines --generate-key "%id%"
MongoDB → Couchbase concept mapping:
| MongoDB | Couchbase |
|---|---|
| Database | Bucket |
| Collection | Collection (within a scope) |
| Document | Document |
_id | Document key (META().id) |
| Index | GSI index |
$lookup (join) | SQL++ JOIN |
| Aggregation pipeline | SQL++ SELECT with GROUP BY / window functions |
| Change streams | DCP / Eventing / Kafka connector |
| Transactions | SDK transactions (same semantics) |
# Export DynamoDB table to JSON
aws dynamodb scan --table-name Orders \
--output json | jq -c '.Items[] | with_entries(.value = .value[keys[0]])' \
> /tmp/dynamo-orders.jsonl
# Import to Couchbase
cbimport json -c couchbase://localhost -u Administrator -p "$CB_ADMIN_PASSWORD" \
-b myapp --scope-collection-exp "_default.orders" \
-d file:///tmp/dynamo-orders.jsonl --format lines --generate-key "%orderId%"
DynamoDB → Couchbase concept mapping:
| DynamoDB | Couchbase |
|---|---|
| Table | Collection |
| Item | Document |
| Partition key + sort key | Document key (concatenate: pk::sk) |
| GSI | GSI (same name, different syntax) |
| Streams | DCP / Eventing |
| Transactions | SDK transactions |
| TTL attribute | Document TTL (meta().expiration) |
See references/code-migration.md for MongoDB, PostgreSQL, and DynamoDB driver → Couchbase SDK translations in Node.js, Python, and Java.
Key SQL → SQL++ differences:
NULL → NULL or MISSING (absent field ≠ null)IS NULL → IS NULL OR IS MISSING (or IS NOT VALUED)AUTO_INCREMENT → Sequences (NEXT VALUE FOR) or UUIDJOIN ON fk = pk → JOIN ON field = META(alias).id for key-based joinsLIMIT x OFFSET y → use keyset pagination for large offsets# 1. Verify document count
cbsh --script "query 'SELECT COUNT(*) AS cnt FROM \`myapp\`._default.orders'"
# 2. Sample documents look correct
cbsh --script "query 'SELECT * FROM \`myapp\`._default.orders LIMIT 3'"
# 3. Check for import errors
cat /tmp/import-errors.log
# 4. Create indexes on query fields
cbsh --script "query 'CREATE INDEX idx_orders_status ON \`myapp\`._default.orders(status, createdAt)'"
# 5. Update statistics
cbsh --script "query 'UPDATE STATISTICS FOR \`myapp\`._default.orders INDEX ALL'"
# 6. Run EXPLAIN on key queries to verify index usage
cbsh --script "query 'EXPLAIN SELECT * FROM \`myapp\`._default.orders WHERE status = \"pending\"'"