#5612·FerretDB

findOneAndUpdate returns null when querying nested array field with dot notation

Author: jsyooCreated Mar 30, 2026Updated Jul 20, 2026

Description

findOneAndUpdate returns null when using dot notation to query a nested array field (e.g. 'triggers.identifier': 'value'), while findOne with the same query works correctly.

FerretDB Version

v1.24 (PostgreSQL backend)

Steps to Reproduce

javascript
// Insert a document with nested array field
db.templates.insertOne({
  name: 'test-workflow',
  _environmentId: ObjectId('69ba499642dcb2ae31dc3d78'),
  triggers: [{ identifier: 'test-workflow', type: 'event' }],
  active: true,
});

// findOne works ✅
db.templates.findOne({ 'triggers.identifier': 'test-workflow' });
// Returns the document

// findOneAndUpdate fails ❌
db.templates.findOneAndUpdate(
  { 'triggers.identifier': 'test-workflow' },
  { $set: { lastTriggeredAt: new Date() } },
  { returnDocument: 'after' }
);
// Returns null (expected: the document)

// findOneAndUpdate works with non-nested field ✅
db.templates.findOneAndUpdate(
  { name: 'test-workflow' },
  { $set: { lastTriggeredAt: new Date() } },
  { returnDocument: 'after' }
);
// Returns the document

Expected Behavior

findOneAndUpdate should return the matching document when using dot notation on nested array fields, consistent with findOne behavior.

Actual Behavior

findOneAndUpdate returns null when the query uses dot notation on a nested array field ('triggers.identifier'), even though findOne with the same query finds the document.

Context

This issue affects Novu (notification infrastructure) running on FerretDB. Novu's worker uses findOneAndUpdate with 'triggers.identifier' to look up notification templates, which always fails on FerretDB, making all workflow triggers non-functional.

Novu source reference: https://github.com/novuhq/novu/blob/v2.1.1/libs/dal/src/repositories/notification-template/notification-template.repository.ts#L57

Workaround

Currently using a Novu-specific workaround (passing bridgeUrl in trigger requests to bypass the template lookup). This is not ideal for production use.

Note

This may already be fixed in v2.x. We haven't tested with the latest version yet. If it is, please let us know and we'll upgrade.