findOneAndDelete() - Atomic find and delete

Syntax

collection(collectionName).findOneAndDelete(filter, options)

Parameters

filter (Object, required)

Filter criteria.

options (Object, optional)

OptionsTypeDefaultDescription
projectionObject-Field projection
sortObject-Sorting conditions
maxTimeMSNumber-Maximum execution time
commentString-Operation comments
collationObject-Sorting Rules
hintString/Object-Index Tips
includeResultMetadataBooleanfalseWhether to include complete metadata

Return value

Default returns deleted document object or null (not found).

If includeResultMetadata: true, return:

{
value: <document or null>,
  ok: 1,
  lastErrorObject: { n: 1 }
}

⚠️ IMPORTANT NOTE - MongoDB Driver 6.x Compatibility

monSQLize uses MongoDB Node.js driver 6.x, which makes important changes to the return value format of findOneAndDelete:

Driver 6.x (current version):

  • By default, the document object is returned directly
  • Requires explicit setting of includeResultMetadata: true to return complete metadata

Driver 5.x and earlier:

  • Return complete metadata { value, ok, lastErrorObject } by default

✅ monSQLize processing:

Core Features

Atomic guarantee

//✅ Atomic operations - find and delete in the same transaction
const deletedTask = await collection("tasks").findOneAndDelete({
  status: "pending",
  assignedTo: null
});

if (deletedTask) {
  console.log("Get the task:", deletedTask.taskId);
  //Processing tasks...
}

//❌ Non-atomic - Risk of race conditions
const task = await collection("tasks").findOne({ status: "pending" });
if (task) {
  await collection("tasks").deleteOne({ _id: task._id });
  //During this period other processes may have acquired the same task!
}

Common scenarios

Scenario 1: Task queue consumption

//Get and delete a task from the queue (atomic operation)
async function getNextTask() {
  const task = await collection("taskQueue").findOneAndDelete(
    {
      status: "pending",
      scheduledAt: { $lte: new Date() }
    },
    {
      sort: { priority: -1, scheduledAt: 1 }
    }
  );

  return task;
}

//It is also safe to call multiple workers concurrently
const task = await getNextTask();
if (task) {
  await processTask(task);
}

Scenario 2: Session cleanup

//Delete expired sessions and record
async function cleanupExpiredSession(sessionId) {
  const deletedSession = await collection("sessions").findOneAndDelete({
    sessionId,
    expiresAt: { $lt: new Date() }
  });

  if (deletedSession) {
    console.log(`Cleaned session: ${sessionId}`);
    //Log to audit log
    await collection("auditLogs").insertOne({
      action: "SESSION_EXPIRED",
      userId: deletedSession.userId,
      timestamp: new Date()
    });
  }

  return deletedSession;
}

Scenario 3: Distributed lock release

//Get lock information and delete
async function releaseLock(lockKey, ownerId) {
  const lock = await collection("locks").findOneAndDelete({
    lockKey,
    ownerId,
    expiresAt: { $gt: new Date() }
  });

  if (!lock) {
    throw new Error("The lock does not exist or is already held by another process");
  }

  console.log(`Lock released: ${lockKey}`);
  return lock;
}

Differences from other methods

FeaturesfindOneAndDeletedeleteOnedeleteMany
Return valueDeleted documentsDeletion statisticsDeletion statistics
Atomic✅ Atomic operations✅ Atomic operations✅ Atomic operations
Get old value✅ Supported❌ Not supported❌ Not supported
Delete quantityMaximum 1Maximum 1Multiple