Update using $cond

Hello,

I have this query that doesn’t work…

I keep getting the following error when trying to update localTimestamp:

MongooseError [CastError]: Cast to date failed for value "{
  '$cond': {
    if: { '$eq': [Array] },
    then: 2023-11-19T14:25:30.788Z,
    else: '$localTimestamp'
  }
}" at path "localTimestamp"

However, if i use timestamp directly, it works (commented out)

I do not wish to make a read-update-write…

Help would be much appreciated!

const timestamp = moment.utc(new Date()).toDate();

const roomDoc = await Acc.findOneAndUpdate(
    {
        _id: accId,
        status: 'active',
    },
    {
        $set: {
            exampleField: 'works',
            // localTimestamp: timestamp, // works
            localTimestamp: {$cond: {if: { $eq: [{ $size: '$exampleArray' }, 0]}, then: timestamp, else: '$handshakeTimestamp'}} // doesn't work
        },
        $addToSet: {
            exampleArray: 'hmmz'
        }
    },
    {
        new: true,
        runValidators: true
    }
);
1 Like

Hi James,

Please include example docs, exact errors and outputs for your scenarios.

https://mongoplayground.net/ can also be useful for sharing data + queries.

Since you want to use $cond in the update query, you have to wrap you update config in the array, which would allow you to use aggregate options in the update query:

await Acc.findOneAndUpdate(
    {
        _id: accId,
        status: 'active',
    },
    [
      {
          $set: {
              exampleField: 'works',
              localTimestamp: {$cond: {if: { $eq: [{ $size: '$exampleArray' }, 0]}, then: timestamp, else: '$handshakeTimestamp'}}
          },
          $addToSet: {
              exampleArray: 'hmmz'
          }
       },
    ],
    {
        new: true,
        runValidators: true
    }
);

Note: Make sure that exampleArray field exists on the document and is of type array. Otherwise, the query will throw the error because you would try to calculate the $size of the non-array field.

thanks!

thing is, mongoplayground doesn’t recognize findOneAndUpdate

instead of the line:

    localTimestamp: new Date()

I’d like to add a condition that checks if the array exampleArray is empty. if it is - set localTimestamp with the current timestamp

https://mongoplayground.net/p/2I92JhdPnOL

cheers

Here is the working example.

thanks @NeNaD , thing is, this is without addToSet

when I try to use it in my code, I get the same error, or that it simply doesn’t update the document.
https://mongoplayground.net/p/5a4PFmN8xQw

The code works perfectly. The else: clauses specify $handshakeTimestamp and $localTimestamp respectively. Since $handshakeTimestamp does not exist in the source document, you get undefined. As for $localTimestamp it is undefined in the original documents and that is what you get in the results.

About mongoplayground, does anyone know the lifespan of link?

I am worry that we can lose the solution whenever a playground link expire.

Shared Playgrounds

Shared playgrounds are saved forever.

Do not share playground containing sensitive data, as they can get accessed by anyone who get the playground link!

1 Like

Saru mo ki kara ochiru

I looked at that page before I asked and skipped that sentence completely. I must work on my diagonal reading skills.

Thanks

@steevej the code works perfectly in mongoplayground, that’s true. however, doing so in my project - fails.

thanks for the assistance!

It looks like Mongoose is in your way and prevents you from doing something that can be done with the native driver. I would try to do this update with the native API rather than the Model object you got from your Schema.