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 المهني
| 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\"'"
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