Skip to main content

MongoDB

MongoDB is a document database. Load collections into MotherDuck with dlt, by exporting newline-delimited JSON, or through a managed change-data-capture connector.

MongoDB stores documents rather than rows, so loading it into MotherDuck is as much a flattening problem as a transfer problem. There is no DuckDB mongodb extension, so collections come across as JSON, either through a tool that handles the schema work or through an export you read yourself.

Load collections with dlt

dlt has a MongoDB source and a MotherDuck destination, and it does the part you'd otherwise write by hand: it infers a schema from the documents, normalizes nested fields into columns and child tables, and evolves the schema as the documents change.

dlt init mongodb motherduck
pip install -r requirements.txt

Set the MongoDB connection string and your MotherDuck token, then run the pipeline:

export MOTHERDUCK_TOKEN="<motherduck_token>"
export SOURCES__MONGODB__CONNECTION_URL="mongodb+srv://<user>:<password>@<cluster>/"
python mongodb_pipeline.py

Configure which collections to load, and whether to load incrementally, in the generated pipeline script. See the dlt MongoDB source documentation for the source options.

Export JSON and read it

For a one-time load or a small collection, export with mongoexport and read the file. The default output is one JSON document per line, which DuckDB reads natively:

mongoexport \
--uri="mongodb+srv://<user>:<password>@<cluster>/<database>" \
--collection=orders \
--out=orders.json
CREATE TABLE orders AS
SELECT * FROM read_json('orders.json', format = 'newline_delimited');

DuckDB infers a schema from a sample of the documents, so nested objects become STRUCT columns and arrays become LIST columns. For a large export, write it to object storage and read from there instead of your local machine:

CREATE TABLE orders AS
SELECT * FROM read_json(
's3://my-bucket/mongo-export/orders/*.json',
format = 'newline_delimited'
);

Use a managed connector

If you want a scheduled sync without writing pipeline code, several MotherDuck ingestion partners list MongoDB as a source: Airbyte, Fivetran, Estuary, and Streamkap. Streamkap and Estuary read MongoDB's change stream, so they suit change-data-capture rather than full reloads.

Things to know

  • Extended JSON leaks into your columns. mongoexport writes BSON types as wrapper objects, so _id arrives as an object with an $oid key and dates as objects with a $date key. Project the values you want out of those wrappers after loading, or restrict the export with --fields to skip the types you don't need. dlt handles this conversion for you.
  • Schema inference samples. read_json infers types from the first documents it sees, so a field that only appears later, or changes type between documents, can be missed. Pass an explicit columns argument for a stable load, or set union_by_name = true when reading many files.
  • Flatten before you query. Querying STRUCT and LIST columns works, but downstream BI tools generally expect flat columns. Unnest the fields you report on into a curated table rather than making every consumer walk the document structure.
  • MongoDB stays the write path. MotherDuck is analytical. Keep application writes in MongoDB and treat MotherDuck as the read side for reporting.