Update document only if the latest element in object array match

Hi guys, I’m trying to update a document only if the _id of the latest element in the array is equal to the provided, considering the transaction needs to be atomic.

(I’m using mongoose)

schema

{
  _id: ObjectId,
  ok: Boolean,
  myArray: [
    {
      _id: ObjectId,
      user: ObjectId,
      createdAt: Date,
    }
  ]
}

Currently, I’m trying to do this:

db.collection.findOneAndUpdate(
  { 
     _id: ObjectId('63d6fd0a14953235d7880dfd'),
    'myArray.$._id': ObjectId('63d6fbcc01ba646ee2e2b37f')  // <-- Here
   },
  { $set: { ok: true } },
  {
   $sort: { 'myArray.createdAt': -1 }
  }
);

Does anyone know how to do this atomically?

Thanks!

Hello @Matias_Lopez ,

Welcome to The MongoDB Community Forums! :wave:

I notice you haven’t had a response to this topic yet - were you able to find a solution? If not then please confirm if my understanding of your use-case is correct. I believe you want to do the findOneAndUpdate() operation atomically.

As per the documentation on Atomicity and Transactions

In MongoDB, a write operation is atomic on the level of a single document, even if the operation modifies multiple embedded documents within a single document.

So as you are updating just one document while using findOneAndUpdate() hence MongoDB will make sure the operation is atomic.

Additionally, is your query working as expected? if not can you share below details for me to understand your use-case better?

  • Share some sample documents
  • I’m not sure what do you mean by _id of the latest element, are you referring to the createdAt date in myArray? If yes, then my understanding is that you have multiple objects in myArray and want to update ok: true based on latest object in array by sorting createdAt only if _id(from latest object) matches the provided _id in query. Could you please confirm if this is your requirement?

Regards,
Tarun

Hi @Tarun_Gaur! Yes, I confirm.

I want to update the document’s root properties only if the latest element on myArray matches the provided _id. The important thing is trying to update something if the latest element of an array match with another thing, in this case, _id, but could be Date, String, Number, etc.

I think the best strategy to do this is sorting myArray based on the createdAt key, for after the update stage setting the ok root property as true, but sort myArray is not a requirement.

Regards!

Something like the following should work.

db.collection.findOneAndUpdate(
  { 
     _id: ObjectId('63d6fd0a14953235d7880dfd'),
    "$expr" : { 
       "$eq" : [ { "$last" : "myArray._id" } , ObjectId("63d6fbcc01ba646ee2e2b37f") ]
    } 
   },
  { $set: { ok: true } },
  {
   $sort: { 'myArray.createdAt': -1 }
  }
);
1 Like