Skip to main content

MongoDB Module

Read and write your own MongoDB database from a workflow: MongoDB Atlas, Azure Cosmos DB for MongoDB, or a server you run. Three tasks cover what a flow needs: Find documents, Save documents and Delete documents, with the flow's variables bound into the queries.

Typical uses: look a customer up by the email a chat or form gave you, record every order or conversation as a document, keep a counter or a status up to date with $inc and $set, feed a list of documents to an AI task or an email, or report on a collection with an aggregation pipeline.

Requirements​

  • A MongoDB cluster the engine can reach, and a database user with the roles the flows need (readWrite on one database is enough for most flows; read for report-only flows).
  • On Atlas, the engine's outbound IP must be in the project's IP access list.

Configuration​

SettingRequiredNotes
Connection stringyesmongodb:// or mongodb+srv://, with the user and password. Atlas: Database → Connect → Drivers. Stored securely; never shown in logs or errors.
DatabaseyesThe database the tasks use. A task can name another one in its advanced options.
Default timeout (seconds)no1–300. Empty: 30. A task can set its own.

Writing queries​

Filters, documents, updates and pipelines are the JSON you would type in the MongoDB shell (mongosh): quoted or unquoted keys, ObjectId("…"), ISODate("…"), {"$gte": 10}, and so on.

Variables are bound by type, not pasted as text. Write a flow variable without quotes and the task binds it the way a database driver binds a parameter:

You writeWithThe server receives
{"email": {email}}email = ann@example.com{"email": "ann@example.com"}
{"total": {"$gte": {minTotal}}}minTotal = 100 (a number){"total": {"$gte": 100}}
{"status": {"$in": {statuses}}}statuses = a list{"status": {"$in": ["open", "paid"]}}
{record}record = an objectthe object as the document
{"createdAt": {"$lt": {execution.startedAt}}}a datea BSON date

A text value is always quoted and escaped, so a visitor's input can never add keys or operators to your query. A variable that does not exist binds as null.

Inside a string a variable is just text: {"_id": ObjectId("{customerId}")}, {"note": "Order {orderNumber} from {name}"}, ISODate("{since}").

Numbers typed in a form arrive as text. To compare them as numbers, compute a numeric variable first (a JavaScript task, a Date task) or compare on the text field the collection stores.

Results come back as plain variables: a list of documents ({orders.0.customer.name}, {orders.0._id}), one document ({customer.email}), a number or a list of values. Ids are text: an ObjectId is its 24-character hex, ready for ObjectId("{id}") in a later filter. Dates are dates, numbers are numbers, sub-documents and arrays keep their shape.

Find documents​

One task with five operations. The result is written to the Output variable.

OperationReturnsFields
Find documentsa list of documentsFilter, Maximum documents (1–5000, empty: 100), Sort, Projection, Skip
Find one documentthe first match, or nothingFilter, Sort, Projection, optional Found variable (true / false)
Count documentsa numberFilter
Distinct valuesa list of valuesField (dotted paths work: address.city), Filter; at most 5000 values
Aggregate (pipeline)a list of documentsPipeline (a JSON array of stages), Maximum documents (added as a final $limit, except after $out / $merge)
PropertyNotes
CollectionThe collection name; a {variable} works.
FilterMongoDB query document. Empty or {}: every document.
Sort{"createdAt": -1, "name": 1}: 1 ascending, -1 descending. Advanced.
Projection{"name": 1, "email": 1} keeps those fields (and _id); {"notes": 0} drops one. Advanced.
SkipDocuments to skip, for paging. Advanced.
Database, TimeoutPer-task overrides of the module configuration. Advanced.

Example, the open orders of the customer who wrote in:

Operation:  Find documents
Collection: orders
Filter: {"customerEmail": {email}, "status": "open"}
Sort: {"createdAt": -1}
Output: {orders}

Then {orders.0.total} is the latest order's total, and a Switch on {orders} being empty routes customers with no open order.

Save documents​

OperationFieldsResult outcome
Insert one documentDocumentinserted; {result.insertedId} is the new _id as text
Insert many documentsDocuments (a JSON array or a {list} variable, up to 5000)inserted; {result.insertedIds}
Update one documentFilter, Update, Upsertupdated, unchanged, not_found or upserted
Update many documentsFilter, Update, Upsertsame, with {result.matchedCount} and {result.modifiedCount}
Replace one documentFilter, Document, Upsertsame

Update takes update operators only: {"$set": {"status": "closed"}, "$inc": {"visits": 1}, "$push": {"log": {entry}}, "$currentDate": {"updatedAt": true}}. A plain key at the top level is refused; to swap the whole document use Replace one document.

Upsert inserts when the filter matches nothing: for an update, the document is built from the filter's equalities and the update's values.

The optional Result variable receives { insertedId, insertedIds, insertedCount, matchedCount, modifiedCount, outcome }.

Example, one document per customer, created on first contact and updated after:

Operation:  Update one document
Collection: customers
Filter: {"email": {email}}
Update: {"$set": {"name": {name}, "lastContact": {execution.startedAt}}, "$inc": {"contacts": 1}}
Upsert: on
Result: {saved}

{saved.outcome} is upserted the first time and updated after.

Delete documents​

OperationNotes
Delete one documentThe first document the filter matches.
Delete many documentsEvery document the filter matches.

Filter is required and must not be empty: a blank variable can never wipe a collection by accident. To empty a collection on purpose, use Delete many documents and turn on Allow an empty filter in the advanced options.

The optional Result variable receives { deletedCount }.

Errors​

Every task takes its error flow on a failure and writes {mongoError} with code, message (a short sentence safe to show an end user) and detail (the server's own text, for the author; also in the step's log). Route on {mongoError.code} with a Switch:

CodeWhen
duplicate_keyA write hit a unique index (_id or another unique key): the conflict to route as a business case.
invalid_inputA task field is missing or out of range (an empty collection, a limit above 5000, an update without operators, an empty delete filter).
invalid_jsonA filter, document, update or pipeline is not valid JSON once the variables are bound.
configurationNo connection string or database, or a malformed connection string.
connectionThe server could not be reached (host, port, DNS, TLS, IP access list).
authenticationThe server refused the user or password.
unauthorizedThe user may not run that operation on that database or collection.
timeoutThe operation took longer than the timeout.
write_errorThe server rejected a write for another reason (a schema validation rule, say).
command_errorThe server rejected the query (a bad pipeline stage, an unknown operator): detail has the server's message.
too_manyMore than 5000 distinct values, or more than 5000 documents to insert at once.

Connection strings never appear in messages: a driver text that echoes one has its credentials replaced by ***.

Limits​

  • At most 5000 documents per Find or Aggregate (set Maximum documents; page with Skip), 5000 distinct values, 5000 documents per Insert many.
  • One operation per task; there are no multi-document transactions. Model a transaction as an upsert with a unique key, or keep the state in one document and change it with operators.
  • The tasks use the BsonDocument shape: field names are kept exactly as stored, including _id.