When to Use
- Customer lookup for personalisation: At the start of a marketing or onboarding workflow, query the
customers collection filtering by customerId to retrieve the customer's tier, preferences, and contact details. Use the returned document fields to personalise email content, select the right communication channel, and apply appropriate discount logic.
- Order processing queue: A scheduled workflow queries the
orders collection for all documents where status = "pending" and createdAt is older than 24 hours. Pass the resulting documents array to a Loop node and process each overdue order — send fulfilment alerts, escalate to the warehouse team, or notify the customer.
- SaaS multi-tenant dashboard data: Query user activity records filtered by
tenantId with a projection to return only userId, lastLogin, and planTier. Sort by lastLogin: -1 to produce a recent-activity list for the tenant admin dashboard without exposing sensitive internal fields.
- Inventory reorder detection: A nightly scheduled workflow queries the
products collection for all items where stockQty is less than reorderThreshold. The resulting list is passed to a procurement notification workflow, generating purchase orders per supplier.
- HR compliance reporting: Query the
employees collection filtering by department, startDate range, and trainingCompleted: false to produce a list of employees overdue for mandatory compliance training. Feed results into an email batch-send workflow.
Configuration
Connection
| Field | Required | Description |
ConnectionUri | Required | MongoDB connection string. Reference via {{ $credentials.mongodbAtlas }}. |
Database | Required | Target database name. Example: ecommerce. |
Collection | Required | Target collection name. Example: orders. |
Operation
| Field | Required | Description |
Query | Optional | MongoDB query filter as a JSON object. Default {} matches all documents. Use standard MongoDB query operators: $eq, $gt, $in, $and, $or, $regex, etc. Example: {"status": "pending", "total": {"$gt": 100}}. Supports BizFirst expressions for dynamic filtering. |
Limit | Optional | Default 100. Maximum number of documents to return. Set to a low value (10–50) for interactive lookups. Increase for batch processing workflows — but always set an explicit limit; avoid leaving this at the default on large collections without a scoped filter. |
Sort | Optional | Sort specification as a JSON object. Key is field name, value is 1 (ascending) or -1 (descending). Example: {"createdAt": -1} returns newest first. Multiple fields supported: {"status": 1, "createdAt": -1}. |
Projection | Optional | Field inclusion or exclusion map. Use 1 to include, 0 to exclude. Cannot mix inclusion and exclusion (except for _id). Example inclusion: {"orderId": 1, "status": 1, "total": 1, "_id": 0}. Reduces payload size and network transfer — always project when you only need a subset of fields. |
Sample Configuration
Query the 50 most recent pending orders for a specific customer, returning only the fields needed for the fulfilment notification:
{
"resource": "document",
"operation": "find",
"ConnectionUri": "{{ $credentials.mongodbAtlas }}",
"Database": "ecommerce",
"Collection": "orders",
"Query": {
"customerId": "{{ $json.customerId }}",
"status": "pending",
"createdAt": { "$gte": "{{ $json.sinceDate }}" }
},
"Limit": 50,
"Sort": { "createdAt": -1 },
"Projection": {
"orderId": 1,
"status": 1,
"total": 1,
"shippingAddress": 1,
"lineItems": 1,
"createdAt": 1,
"_id": 0
}
}
Validation Errors
| Error | Cause |
connectionUri is required | ConnectionUri is empty or not provided. |
database is required | Database field is empty or whitespace. |
collection is required | Collection field is empty or whitespace. |
Avoid empty queries on large collections. A Query: {} with Limit: 100 performs a full collection scan and returns up to 100 arbitrary documents. On collections with millions of records this is slow and expensive. Always include a filter that matches an indexed field, or set Limit intentionally small for exploratory queries.
Output — Success Port
| Field | Type | Description |
count | integer | Number of documents returned in this result set. Equal to or less than Limit. |
documents | array | Array of document objects matching the query. Each element is a full document (or projected subset) as returned by MongoDB. |
status | string | Always "success". |
resource | string | Always "document". |
operation | string | Always "find". |
Sample Output
{
"count": 2,
"documents": [
{
"orderId": "ORD-2024-001847",
"customerId": "CUST-10293",
"status": "pending",
"total": 125.91,
"shippingAddress": {
"line1": "42 Elm Street",
"city": "Austin",
"state": "TX",
"zip": "78701"
},
"lineItems": [
{ "sku": "SHOE-BLK-42", "qty": 1, "unitPrice": 89.99 },
{ "sku": "SOCK-WHT-M", "qty": 3, "unitPrice": 9.99 }
],
"createdAt": "2024-11-14T22:14:09.000Z"
},
{
"orderId": "ORD-2024-001802",
"customerId": "CUST-10293",
"status": "pending",
"total": 44.50,
"shippingAddress": {
"line1": "42 Elm Street",
"city": "Austin",
"state": "TX",
"zip": "78701"
},
"lineItems": [
{ "sku": "HAT-RED-OS", "qty": 2, "unitPrice": 22.25 }
],
"createdAt": "2024-11-13T17:05:33.000Z"
}
],
"status": "success",
"resource": "document",
"operation": "find"
}
Expression Reference
| Expression | Returns | Description |
{{ $output.FindOrders.count }} | integer | Total number of documents returned. Use in an IfCondition node: branch on count == 0 to handle empty results. |
{{ $output.FindOrders.documents }} | array | Full document array. Pass directly to a Loop node's Items field to iterate over each result. |
{{ $output.FindOrders.documents[0] }} | object | First document in the result set. Use when you expect exactly one result (e.g. lookup by unique key). |
{{ $output.FindOrders.documents[0].orderId }} | string | Access a specific field on the first document. |
{{ $output.FindOrders.documents[0].total }} | number | Numeric field from the first document — usable directly in arithmetic expressions. |
{{ $output.FindOrders.documents[0].shippingAddress.city }} | string | Access a nested field using dot notation on the document object. |
{{ $output.FindOrders.documents | length }} | integer | Alternative to count — compute array length inline. |
Node Policies & GuardRails
| Policy | Recommendation |
| Credential storage | Always reference the ConnectionUri from BizFirst Credentials Manager. Never embed usernames or passwords in workflow expressions. |
| Always set a Limit | The default limit of 100 is a safety cap, not a pagination strategy. Explicitly set Limit based on your use case. For batch workflows feeding a Loop node, keep it at or below 500 to avoid memory pressure per execution step. |
| Index all query fields | Every field used in the Query filter should have an index in MongoDB. Create compound indexes for multi-field queries. Unindexed queries perform full collection scans and slow down under load. |
| Projection to reduce payload | Use Projection to return only the fields your workflow actually needs. This reduces data transfer, speeds up execution, and avoids exposing sensitive fields in workflow logs. |
| Multi-tenant isolation | Always include tenantId in the Query filter for multi-tenant applications. A missing tenantId filter could return documents from other tenants. |
| Empty result handling | Connect the success port to an IfCondition node that checks count == 0. Downstream nodes that expect documents will fail with null-reference errors if the array is empty and no guard is present. |
| Rate limiting for loops | If the result feeds a Loop node that makes external API calls per document, add a Delay node inside the loop to avoid rate-limiting downstream services. |
| Sort with an index | Sorting on unindexed fields in large collections forces an in-memory sort and can trigger MongoDB's 100 MB sort memory limit. Ensure the sort field has a supporting index, or use an aggregation pipeline with $sort + allowDiskUse. |
Workflow Examples
Example 1 — Fetch Pending Orders for Processing
{
"resource": "document",
"operation": "find",
"ConnectionUri": "{{ $credentials.mongodbAtlas }}",
"Database": "ecommerce",
"Collection": "orders",
"Query": { "status": "pending" },
"Limit": 200,
"Sort": { "createdAt": 1 },
"Projection": { "orderId": 1, "customerId": 1, "total": 1, "lineItems": 1, "_id": 0 }
}
Example 2 — Customer Lookup by ID (Single Result)
{
"resource": "document",
"operation": "find",
"ConnectionUri": "{{ $credentials.mongodbAtlas }}",
"Database": "crm",
"Collection": "customers",
"Query": { "customerId": "{{ $json.customerId }}", "tenantId": "{{ $json.tenantId }}" },
"Limit": 1,
"Projection": { "name": 1, "email": 1, "tier": 1, "preferences": 1, "_id": 0 }
}
Example 3 — Employees Overdue for Compliance Training
{
"resource": "document",
"operation": "find",
"ConnectionUri": "{{ $credentials.mongodbHR }}",
"Database": "hrcore",
"Collection": "employees",
"Query": {
"department": "{{ $json.department }}",
"trainingCompleted": false,
"startDate": { "$lte": "{{ $json.cutoffDate }}" }
},
"Limit": 500,
"Sort": { "startDate": 1 },
"Projection": { "employeeId": 1, "name": 1, "email": 1, "department": 1, "startDate": 1, "_id": 0 }
}