Connecting MongoDB to n8n: the native node, its operations, and its pitfalls
Published 13 August 2026 · 7 min read
MongoDB has become the go-to database for anything that doesn't fit cleanly into rows and columns: product catalogs with variable attributes, heterogeneous form responses, event logs, scraped content that's already JSON. It's also the database behind a large share of modern SaaS applications and Node.js projects, which makes it a frequent target for n8n whenever you need to sync, migrate, or query that data from a workflow. n8n's native MongoDB node covers this natively, with a JSON query syntax close to the mongosh shell — quite different from the SQL of the Postgres and MySQL nodes we've already covered. This guide walks through the connection, the seven available operations, the classic ObjectId trap, and protection against NoSQL injection.
MongoDB vs Postgres and MySQL in n8n: when to pick which
The choice often isn't really yours to make: a MongoDB database already exists (a Node.js app, a third-party SaaS, a JSON export) and n8n just needs to connect to it, exactly like in our MySQL node guide. But for a new project built from scratch, the question is worth asking:
- Stable, relational schema (customers, orders, invoices linked to each other) → PostgreSQL stays the default choice: native joins, integrity constraints, and the pgvector ecosystem if a RAG use case gets added later.
- Variable or nested schema (each document has different fields, arrays of sub-objects, a structure that evolves with every new source) → MongoDB avoids the painful choice between a table riddled with NULL columns and a cascade of junction tables to represent nested JSON.
- A third party already imposes the format: an API that responds with deeply nested JSON, an export from an app that stores data natively in MongoDB — replicating that structure as-is is often faster than flattening it into columns.
A study by Li and Manoharan, A performance comparison of SQL and NoSQL databases, published in the proceedings of IEEE PACRIM 2013 (Google Scholar), compared read, write, delete, and instantiate operations across several SQL and NoSQL databases: the headline result is that neither family consistently dominates — performance depends on the specific operation and engine tested, not on some generic superiority of the document model over the relational model (or vice versa). The relevant selection criterion is the shape of your data, not a promise of raw speed.
Connecting: connection string or separate values
n8n's MongoDB credential offers two configuration modes:
- Connection String — the most common format with MongoDB Atlas: paste the URI Atlas gives you directly (
mongodb+srv://user:password@cluster.mongodb.net/?retryWrites=true&w=majority). This is the recommended mode whenever the cluster uses themongodb+srv://protocol, which encodes replica-set node discovery. - Values — host, port (27017 by default), database, user, and password entered separately. Useful for a self-hosted MongoDB server in Docker or on a VPS, without Atlas-managed DNS.
With MongoDB Atlas, two steps come before connecting from n8n: add your n8n instance's IP address to the cluster's network access list, and create a database user with the required permissions (Database Access) — an Atlas login account is not automatically a database user. The free M0 cluster is more than enough to test a workflow before moving to a paid tier.
In local Docker, as with Postgres and MySQL, the host to enter in the credential is the Docker service name (mongo or mongodb, depending on your docker-compose.yml), never localhost, which would point to the n8n container itself.
The seven operations of the MongoDB node
The node exposes a broader palette than its SQL cousins, reflecting the document model:
- Find — searches documents against a JSON filter, with sorting, projection (which fields to return), and pagination.
- Insert — adds one or more documents to a collection.
- Update — modifies documents matching a filter, using MongoDB operators (
$set,$inc,$push…) rather than a simple value replacement. - Delete — removes documents matching a filter.
- FindOneAndUpdate — finds a document and updates it in a single atomic operation, with the option to return the document before or after the change.
- FindOneAndReplace — finds a document and replaces its entire content, rather than merging fields.
- Aggregate — runs a full MongoDB aggregation pipeline (
$match,$group,$lookup,$project…), the equivalent of SQL joins andGROUP BY.
Recent versions also add Atlas Search index management operations (create, list, update, drop a search index) — relevant only if your cluster uses Atlas Search, with no equivalent on a generic MongoDB install.
Unlike the Postgres node, there's no dedicated "Upsert" operation: that behavior is achieved via Update or FindOneAndUpdate by enabling the Upsert option, which inserts a new document when no document matches the filter.
Writing the filter: the Query field's JSON syntax
This is the main shift for anyone coming from Postgres or MySQL: where those nodes offer structured fields (column, operator, value), the MongoDB node expects a raw JSON object, mongosh-shell style:
{
"status": "pending",
"amount": { "$gte": 100 },
"createdAt": { "$gte": { "$date": "2026-08-01T00:00:00Z" } }
}
This format works well with n8n expressions injected into values ({{ $json.status }}), but requires knowing MongoDB operators ($gte, $in, $exists, $regex…) rather than plain SQL WHERE clauses. For aggregation, the Pipeline field expects a JSON array of stages, exactly like a db.collection.aggregate([...]) pipeline copied from mongosh or Compass — a good habit is to prototype the pipeline in Compass first, rather than building it blind inside the node.
The classic trap: ObjectId
MongoDB's _id field is not a plain string but a specific binary type, the ObjectId. A common mistake is filtering with {"_id": "{{ $json.id }}"}: the comparison fails silently, with no error, and simply returns no document, because MongoDB compares an ObjectId to a string and never finds a match. The correct syntax wraps the value with the JSON extension the driver expects:
{ "_id": { "$oid": "{{ $json.id }}" } }
The same principle applies to dates ({"$date": "..."}) and other BSON types with no native JSON equivalent. This forgotten conversion, together with confusing Update (which merges fields via operators) with FindOneAndReplace (which replaces the entire document), is the most frequent source of errors for anyone new to this node coming from the SQL world.
NoSQL injection: the risk exists on MongoDB too
The MongoDB node's free-text Query field poses the same underlying problem as the Execute Query field of a SQL node exposed to untrusted input: a string dynamically built from external data (a form, a webhook, an LLM's output) can inject unexpected MongoDB operators instead of a simple value. A reference paper on the topic, Ron, Shulman-Peleg & Bronshtein, No SQL, No Injection? Examining NoSQL Security (2015, arXiv — Google Scholar), documents how operators like $where (which executes server-side JavaScript) or $ne can be injected into a poorly built MongoDB query to bypass an authentication filter or extract out-of-scope data.
The countermeasure on the n8n side: never build the Query field by concatenating a raw string from an external input into a JSON object. Prefer injecting the value inside a JSON key you already fixed yourself ({"email": "{{ $json.email }}"}) rather than letting external input supply the filter's structure itself. If a use case genuinely requires building filter keys dynamically (multi-criteria search from a form, for instance), explicitly validate and allow-list the permitted fields in a Code node before composing the JSON object sent to the MongoDB node.
Concrete n8n use cases
- Syncing a heterogeneous product catalog to a site or marketplace: each product has different attributes (size, color, capacity, material) that fit naturally into a MongoDB document but would force a SQL table into a painful EAV model. A scheduled workflow reads documents modified since the last sync (an
updatedAtfield filtered with$gte) and pushes the changes to the site's API. - Centralizing application event logs — received webhooks, AI agent runs, errors — in a MongoDB collection rather than a rigid SQL table, then querying those logs with Aggregate to produce a summary report, on the same principle as the audit trail described for Supabase, adapted to document storage when the event format varies too much for a fixed table.
- Feeding a RAG pipeline from Atlas Search: MongoDB Atlas has its own vector search engine, an alternative to the Supabase/pgvector setup covered in our RAG with Supabase guide — relevant when the source documents already live in MongoDB and there's no reason to duplicate them elsewhere. The RAG Assistant Pack (€119) is built on Supabase/pgvector, but the same ingestion pattern (chunking, embeddings, similarity search) maps onto the MongoDB Aggregate node with the
$vectorSearchoperator.
Setup checklist
- Credential configured as Connection String (Atlas) or Values (self-hosted server), with n8n's IP whitelisted on the Atlas side if applicable.
- The Query field's JSON filter tested against a development dataset before production, with ObjectIds and dates correctly wrapped (
$oid,$date). - A clear distinction between Update (merge via operators) and FindOneAndReplace (full replacement) before writing to a production collection.
- No unfiltered external input directly composes the structure of the JSON filter sent to the node.
- Aggregate pipelines prototyped in Compass or
mongoshbefore being pasted into n8n.
MongoDB in n8n takes some adjustment if your instinct is SQL — the filter's JSON syntax and the distinction between update operations have no direct equivalent in the Postgres or MySQL nodes. But for data whose shape legitimately varies from one record to the next, it's often the shortest path between a third party's API and an n8n workflow that works without forcing a schema onto it.
FAQ
Frequently asked questions
Do I need a MongoDB Atlas account to use n8n's MongoDB node?
No. The node connects to any network-reachable MongoDB server — Atlas (the managed service), a self-hosted instance in Docker, or a plain MongoDB server on a VPS. Atlas simply simplifies getting started (free M0 cluster, one-click IP whitelisting) and adds proprietary features like Atlas Search, absent from a generic MongoDB install.
Does n8n's MongoDB node automatically protect against NoSQL injection?
Partially. Structured operations (Insert, Update, Delete with a simple matching field) escape values correctly. The risk remains on free-text query fields — the Query field in Find, or an entire Aggregate pipeline body — where an n8n expression inserts a string directly into a JSON object interpreted by MongoDB. An attacker who controls that string can inject operators like $where or $ne to alter the filter's logic.
How do I retrieve a MongoDB document by its _id from n8n?
The _id field is stored as an ObjectId, not a plain string. In the Query field of the Find operation, wrap the value with the syntax the MongoDB driver expects, e.g. {"_id": {"$oid": "{{ $json.id }}"}} rather than a bare string — without this conversion, the comparison fails silently and returns no results.
MongoDB or PostgreSQL for a new project automated with n8n?
If the data has a stable structure with relationships between records (orders linked to customers, invoices linked to line items), PostgreSQL with the Postgres node stays simpler to query and easier to enforce with constraints. MongoDB wins when the schema varies from one document to the next (heterogeneous form responses, event logs, scraped content) or when a third party already imposes that format — fighting the document model to force it into relational tables costs more than just accepting it.
Bundle FlowKit Complet
€269