Irreversible operation. Deleted documents cannot be recovered unless you have a separate backup or soft-delete architecture in place. Always verify your query filter using
document/find first to confirm the exact documents that will be removed. Never use
Query: {} with
DeleteMany: true in production — this deletes every document in the collection.
When to Use
- GDPR / right-to-erasure compliance: When a verified account deletion request is received, permanently delete all personal data documents belonging to the customer across multiple collections — profile, activity log, preferences. Use
DeleteMany: true scoped to customerId to clean up all associated records in one step per collection.
- Expired session cleanup: A nightly scheduled workflow removes session documents where
expiresAt is in the past. With DeleteMany: true and a date-range filter, the entire backlog of expired sessions is purged in a single operation, keeping the sessions collection lean.
- Temporary processing record removal: A multi-step workflow creates intermediate staging documents as it processes data. After the final step succeeds, a cleanup node deletes those staging documents by their
workflowRunId. This prevents the staging collection from growing unbounded.
- Test data teardown: A post-test cleanup workflow running in a CI pipeline deletes all documents tagged with
environment: "test" and runId: "{{ $ciRunId }}", resetting the database to a clean state for the next test run.
- Cancelled subscription data removal: When a customer cancels and requests data deletion after a retention period, a scheduled workflow identifies all collections with tenant-scoped data and deletes those documents, then archives the deletion event to an immutable audit log before the permanent removal.
Configuration
Connection
| Field | Required | Description |
ConnectionUri | Required | MongoDB connection string. Reference via {{ $credentials.mongodbAtlas }}. |
Database | Required | Target database name. |
Collection | Required | Target collection name. |
Operation
| Field | Required | Description |
Query | Optional | Filter identifying documents to delete. Default {} matches all documents — use only when intentionally wiping a collection (development/test only). Always include precise constraints: IDs, date ranges, status flags, and tenantId for multi-tenant systems. Example: {"customerId": "CUST-10293", "tenantId": "tenant_acme"}. |
DeleteMany | Optional | Default true. When true, all documents matching the filter are deleted. When false, only the first matching document (in natural collection order) is deleted. Set false for single targeted deletions such as removing a specific document by its _id. |
Prefer soft-delete in production systems. For most business data, consider adding a
deletedAt timestamp and
isDeleted: true flag using
document/update instead of permanently removing documents. Soft-delete preserves audit trails and allows recovery. Use hard delete only when legally required (GDPR erasure) or for non-critical cleanup scenarios.
Sample Configuration
Delete all expired session documents older than the current time:
{
"resource": "document",
"operation": "delete",
"ConnectionUri": "{{ $credentials.mongodbAtlas }}",
"Database": "auth",
"Collection": "sessions",
"Query": {
"expiresAt": { "$lt": "{{ $now }}" },
"tenantId": "{{ $json.tenantId }}"
},
"DeleteMany": true
}
Validation Errors
| Error | Cause |
connectionUri is required | ConnectionUri is empty or not provided. |
database is required | Database field is empty. |
collection is required | Collection field is empty. |
Output — Success Port
| Field | Type | Description |
deletedCount | integer | Number of documents permanently deleted. 0 means no documents matched the filter — the success port still fires in this case. |
status | string | Always "success". |
resource | string | Always "document". |
operation | string | Always "delete". |
Sample Output
{
"deletedCount": 312,
"status": "success",
"resource": "document",
"operation": "delete"
}
Expression Reference
| Expression | Returns | Description |
{{ $output.CleanupSessions.deletedCount }} | integer | Number of documents removed. Use in downstream logging nodes or reports to record the volume of deleted data. |
{{ $output.CleanupSessions.status }} | string | Confirm "success" in a conditional branch before proceeding with dependent steps. |
{{ $output.CleanupSessions.deletedCount == 0 }} | boolean | True when no documents were deleted. Use in IfCondition to detect no-op deletes and handle them distinctly from actual deletions. |
Node Policies & GuardRails
| Policy | Recommendation |
| Credential storage | Always reference ConnectionUri from BizFirst Credentials Manager. Never embed raw credentials in workflow node configuration. |
| Verify before delete | Before a delete workflow runs in production for the first time, run the identical Query in a document/find node and inspect the results. Confirm the document set is exactly what you intend to remove. |
| Never use empty query in production | Query: {} with DeleteMany: true deletes the entire collection. If you need this behaviour in development, use a dedicated flag field (e.g. {"environment": "test"}) and scope all queries to that flag. |
| Multi-tenancy filter | Always include tenantId in the Query filter for shared collections. Deleting across tenant boundaries is a critical data integrity failure. |
| Prefer soft-delete | For business-critical collections (customers, orders, invoices), implement a soft-delete pattern using document/update with $set: {isDeleted: true, deletedAt: "{{ $now }}"}. Reserve hard delete for cleanup and GDPR erasure workflows. |
| Archive before delete | For compliance-sensitive scenarios, use document/find to retrieve the documents and insert them into an archive collection before deleting. This preserves recoverable snapshots while satisfying the hard-delete requirement. |
| Index the query filter | Ensure the Query fields are indexed. Unindexed deletes on large collections perform full scans and hold locks longer, blocking concurrent writes. |
| Error port handling | Always connect the error port. A failed delete in a compliance or cleanup workflow should trigger an immediate alert rather than silently completing the parent workflow with partial data removal. |
Workflow Examples
Example 1 — GDPR Right-to-Erasure Customer Data Deletion
{
"resource": "document",
"operation": "delete",
"ConnectionUri": "{{ $credentials.mongodbAtlas }}",
"Database": "crm",
"Collection": "customers",
"Query": {
"customerId": "{{ $json.customerId }}",
"tenantId": "{{ $json.tenantId }}",
"deletionRequestId": { "$exists": true }
},
"DeleteMany": false
}
Example 2 — Expired Token Cleanup (Scheduled Nightly)
{
"resource": "document",
"operation": "delete",
"ConnectionUri": "{{ $credentials.mongodbAtlas }}",
"Database": "auth",
"Collection": "refresh_tokens",
"Query": {
"expiresAt": { "$lt": "{{ $now }}" }
},
"DeleteMany": true
}
Example 3 — Workflow Staging Record Cleanup
{
"resource": "document",
"operation": "delete",
"ConnectionUri": "{{ $credentials.mongodbAtlas }}",
"Database": "workflow_engine",
"Collection": "staging_data",
"Query": {
"workflowRunId": "{{ $execution.id }}",
"stage": "intermediate"
},
"DeleteMany": true
}