Explore the order-state demo
Change MySQL orders and PostgreSQL shipments, then watch one assembled MongoDB document stay current
Use the running playground to see the problem tapstate solves: one operational
object can depend on records owned by different databases. The sample combines
an order in MySQL with its shipments in PostgreSQL and keeps the assembled
views.order_state document current when either source changes.
Complete the Quickstart first. Run every
command on this page from the generated tapstate-demo directory.
Understand the sample
MySQL
orders
Root key: id
PostgreSQL
shipments
Parent key: order_id
Assemble with nest
Transform: assemble
orders.id =
shipments.order_id
MongoDB
views.order_state
One document per order, with related rows in a shipments array.
Initial snapshot, then ongoing changes from both sources.
The playground creates this workspace:
work/
├── source/
│ ├── orders_db.tap.yml
│ └── fulfillment_db.tap.yml
└── pipeline/
└── order_pipeline.tap.ymlorders_dbcaptures the MySQLorderstable.fulfillment_dbcaptures the PostgreSQLshipmentstable.order_pipelineusesnestto embed matching shipments under each order.- The inline
viewmaterializes the result asviews.order_statein the playground's managed MongoDB store. It does not need aserveblock.
The sources use mode: cdc, and the pipeline uses
read_mode: snapshot_and_cdc. The initial rows arrive through Snapshot; later
inserts, updates, and deletes arrive through CDC.
Follow the pipeline
Open order_pipeline under Pipelines in the web application. Use
Monitoring to follow activity and Logs to investigate errors.
Open order_state under Views and select Documents to browse stored
documents. Reload after each change below, or use the direct MongoDB checks
provided.
The optional experiment below changes sample rows with database tools included
in the playground. Run its commands from tapstate-demo. Each change has a
bounded check against MongoDB because pipeline status alone does not verify the
assembled document. No tapstate CLI session is required.
Add a shipment in PostgreSQL
Open a terminal in tapstate-demo. Add a shipment to order 1:
docker compose exec postgres psql -U postgres -d appdb \
-c "INSERT INTO shipments VALUES (7, 1, 'ups', 'pending');"The assembled order should gain a third item in its shipments array. To verify
the result directly with a bounded wait:
uri='mongodb://mongo:27017/views?directConnection=true'
i=0
until docker compose exec -T mongo mongosh --quiet "$uri" \
--eval 'quit((db.order_state.findOne({id:1})?.shipments?.length ?? 0) >= 3 ? 0 : 1)'; do
i=$((i+1))
[ "$i" -lt 60 ] || { echo "shipment did not appear within 60 seconds"; break; }
sleep 1
done
[ "$i" -lt 60 ]Change the order in MySQL
Update the parent record:
docker compose exec mysql mysql -uroot -psecret appdb \
-e "UPDATE orders SET customer='alicia' WHERE id=1;"Wait for the customer field to change without losing the shipment array:
uri='mongodb://mongo:27017/views?directConnection=true'
i=0
until docker compose exec -T mongo mongosh --quiet "$uri" \
--eval 'quit(db.order_state.findOne({id:1})?.customer=="alicia" ? 0 : 1)'; do
i=$((i+1))
[ "$i" -lt 60 ] || { echo "order did not update within 60 seconds"; break; }
sleep 1
done
[ "$i" -lt 60 ]
docker compose exec mongo mongosh --quiet "$uri" \
--eval 'db.order_state.find({id:1}).pretty()'The same document now reflects the MySQL update and still contains the PostgreSQL shipments. Tapstate maintains this object from two independent change streams; it does not run a cross-database SQL join for each read.
Remove the shipment
Delete the shipment you added:
docker compose exec postgres psql -U postgres -d appdb \
-c "DELETE FROM shipments WHERE id=7;"Wait until the shipments array returns to two elements:
uri='mongodb://mongo:27017/views?directConnection=true'
i=0
until docker compose exec -T mongo mongosh --quiet "$uri" \
--eval 'quit((db.order_state.findOne({id:1})?.shipments?.length ?? 0) <= 2 ? 0 : 1)'; do
i=$((i+1))
[ "$i" -lt 60 ] || { echo "shipment was not removed within 60 seconds"; break; }
sleep 1
done
[ "$i" -lt 60 ]The playground configures
REPLICA IDENTITY FULL for this table so PostgreSQL deletes carry the fields
needed to locate the embedded child. When you prepare your own PostgreSQL
source, follow the PostgreSQL CDC requirements.
Inspect and reset the environment
Check the pipeline status and logs in the web application before resetting it.
To reset every sample database and rerun the Quickstart, remain in
tapstate-demo and run:
docker compose down -v
curl -fsSL https://install.tapstate.dev/demo | shThe managed MongoDB instance is part of this disposable playground. It runs without database authentication and also stores tapstate control-plane data. Do not treat it as a tenant or user security boundary, and do not use sensitive or production data in this environment.
Next steps
- Prepare your own source with its connector guide.
- Build a pipeline in the web application.
- For declarative authoring, create a workspace with the optional CLI.
- Learn how nest assembles documents.
- Review view and serve to distinguish managed materialization from external delivery.
- Use Troubleshooting for quickstart, connector, or pipeline failures.