When to Use
- Configuration snapshot replacement: A workflow receives an updated application configuration object from an external API. Use findOneAndReplace to atomically swap out the current config document with the new version in full — no need to track which individual fields changed. Capture the old document via
ReturnNewDocument: false for rollback purposes.
- Product catalogue synchronisation: An e-commerce sync job pulls fresh product data from a supplier feed. For each product, replace the existing catalogue document entirely with the supplier's updated data — ensuring stale fields from the old version are not retained. Use
Upsert: true to create new product entries for items not yet in the catalogue.
- External system record mirroring: A CRM integration workflow receives full contact records from Salesforce via webhook. Replace the corresponding MongoDB contact document with the latest Salesforce payload in its entirety, preserving only the internal
_id for relational consistency.
- Workflow state snapshot: A long-running workflow that spans hours or days writes its complete current state as a single document. On each resume, replace the prior state snapshot with the new full state object rather than patching individual fields, ensuring no stale partial state persists.
- Idempotent import pipelines: A data import workflow processes records from an external source with natural keys (e.g.
externalId). Use findOneAndReplace with Upsert: true to insert new records and fully replace existing ones — making the import safe to re-run without producing duplicates or retaining obsolete fields.
Full document replacement. Unlike
findOneAndUpdate (which applies partial operators), this operation replaces the entire document body. All existing fields not present in the
Replacement object will be permanently deleted. The original
_id is preserved automatically. Use
document/findOneAndUpdate with
$set when you want to update specific fields without disturbing others.
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 to locate the document to replace. Default {} matches the first document. Use a unique identifier (e.g. {"externalId": "PROD-001"} or {"_id": "..."}) to target the correct document. Supports MongoDB query operators. |
Replacement | Optional | The complete new document body as a JSON object. Default {} replaces all fields with an empty document. Do not include _id — MongoDB automatically preserves the original _id. Do not use update operators here — this is a plain document, not an operator expression. Example: {"name": "Widget Pro", "price": 49.99, "category": "tools", "updatedAt": "{{ $now }}"}. |
Upsert | Optional | Default false. When true, if no document matches the Query, MongoDB inserts the Replacement document as a new record. Enables idempotent create-or-replace patterns. |
ReturnNewDocument | Optional | Default false. When false, the returned document is the original document before replacement — use this for audit/rollback capture. When true, the returned document is the replacement document after the write. |
Sample Configuration
Replace a product catalogue entry with the latest supplier data, upserting if not yet present, and return the old document for change-tracking:
{
"resource": "document",
"operation": "find-one-and-replace",
"ConnectionUri": "{{ $credentials.mongodbAtlas }}",
"Database": "catalog",
"Collection": "products",
"Query": {
"externalId": "{{ $json.supplierProductId }}",
"tenantId": "{{ $json.tenantId }}"
},
"Replacement": {
"externalId": "{{ $json.supplierProductId }}",
"tenantId": "{{ $json.tenantId }}",
"name": "{{ $json.productName }}",
"sku": "{{ $json.sku }}",
"category": "{{ $json.category }}",
"price": "{{ $json.price }}",
"currency": "USD",
"stockQty": "{{ $json.stockQty }}",
"images": "{{ $json.images }}",
"specifications": "{{ $json.specs }}",
"lastSyncedAt": "{{ $now }}"
},
"Upsert": true,
"ReturnNewDocument": false
}
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 |
found | boolean | true if a document was found and replaced. false if no match was found (and Upsert is false, meaning no write occurred). When Upsert: true and no match exists, found is false but a new document was inserted. |
document | object | When ReturnNewDocument: false: the original document before replacement. When ReturnNewDocument: true: the replacement document as written. Returns {} when found is false and no upsert occurred. |
status | string | Always "success". |
resource | string | Always "document". |
operation | string | Always "find-one-and-replace". |
Sample Output
Output when ReturnNewDocument: false — returns the document as it was before replacement:
{
"found": true,
"document": {
"_id": "6651a3f2c4e8b9d0a1f23456",
"externalId": "PROD-9821",
"tenantId": "tenant_acme",
"name": "Widget Pro v1",
"sku": "WGT-PRO-001",
"category": "tools",
"price": 44.99,
"currency": "USD",
"stockQty": 142,
"lastSyncedAt": "2024-11-01T08:00:00.000Z"
},
"status": "success",
"resource": "document",
"operation": "find-one-and-replace"
}
Expression Reference
| Expression | Returns | Description |
{{ $output.ReplaceProduct.found }} | boolean | Whether a matching document was found. Branch in IfCondition to detect new inserts (upsert path) vs replacements. |
{{ $output.ReplaceProduct.document }} | object | The full document returned (pre- or post-replacement based on ReturnNewDocument). |
{{ $output.ReplaceProduct.document._id }} | string | The preserved MongoDB _id of the document. |
{{ $output.ReplaceProduct.document.name }} | string | A specific field from the returned document. |
{{ $output.ReplaceProduct.document.price }} | number | Numeric field — the old price (if ReturnNewDocument: false) for change-detection comparisons. |
{{ $output.ReplaceProduct.document.lastSyncedAt }} | string | Timestamp field on the returned document. |
Node Policies & GuardRails
| Policy | Recommendation |
| Credential storage | Always reference ConnectionUri from BizFirst Credentials Manager. Never embed raw connection strings in workflow configuration. |
| Understand full replacement | This operation erases all fields not in Replacement. Before using it, verify there are no system-managed fields (audit history arrays, internal flags) that should be preserved. If partial field updates are needed, use document/findOneAndUpdate with $set instead. |
| Preserve the _id | Do not include _id in the Replacement document. MongoDB preserves the original _id automatically. Including _id with a different value raises an immutable field error. |
| Capture old document for audit | Use ReturnNewDocument: false and insert a follow-up document/insert step to write the captured old document to a change_history collection for full audit trail coverage. |
| Upsert with unique index | When Upsert: true, ensure the Query filter targets fields covered by a unique index to prevent duplicate inserts under concurrent execution. |
| Multi-tenant isolation | Always include tenantId in the Query filter. Replacing a document from the wrong tenant is irreversible. |
| Index the query filter | The Query should target indexed fields. findOneAndReplace performs a collection scan when no index supports the filter, which degrades under concurrent load. |
| Error port handling | Connect the error port to a notification node. A failed replace on a critical document (e.g. config, active session) should alert immediately rather than silently failing. |
Workflow Examples
Example 1 — Idempotent Product Sync from External Feed
{
"resource": "document",
"operation": "find-one-and-replace",
"ConnectionUri": "{{ $credentials.mongodbAtlas }}",
"Database": "catalog",
"Collection": "products",
"Query": { "externalId": "{{ $json.productId }}", "tenantId": "{{ $json.tenantId }}" },
"Replacement": {
"externalId": "{{ $json.productId }}",
"tenantId": "{{ $json.tenantId }}",
"name": "{{ $json.name }}",
"price": "{{ $json.price }}",
"category": "{{ $json.category }}",
"inStock": "{{ $json.inStock }}",
"syncedAt": "{{ $now }}"
},
"Upsert": true,
"ReturnNewDocument": false
}
Example 2 — Application Config Snapshot Replacement
{
"resource": "document",
"operation": "find-one-and-replace",
"ConnectionUri": "{{ $credentials.mongodbAtlas }}",
"Database": "platform",
"Collection": "app_configs",
"Query": { "configKey": "feature_flags", "environment": "production" },
"Replacement": {
"configKey": "feature_flags",
"environment": "production",
"flags": "{{ $json.newFeatureFlags }}",
"updatedBy": "{{ $json.updatedByUserId }}",
"updatedAt": "{{ $now }}",
"version": "{{ $json.configVersion }}"
},
"Upsert": false,
"ReturnNewDocument": false
}
Example 3 — Workflow State Checkpoint
{
"resource": "document",
"operation": "find-one-and-replace",
"ConnectionUri": "{{ $credentials.mongodbAtlas }}",
"Database": "workflow_engine",
"Collection": "execution_state",
"Query": { "workflowRunId": "{{ $execution.id }}" },
"Replacement": {
"workflowRunId": "{{ $execution.id }}",
"workflowId": "{{ $workflow.id }}",
"currentStage": "{{ $json.currentStage }}",
"stageData": "{{ $json.stagePayload }}",
"resumeToken": "{{ $json.resumeToken }}",
"checkpointAt": "{{ $now }}"
},
"Upsert": true,
"ReturnNewDocument": true
}