Positional operator issue

Hi there,

I’m facing a rather interesting issue.

The following query does not update the document.

collection.findOneAndUpdate
(
  {
    foo: {'$in': ['bar']},
    _id: 'someStringId',
    'baz._id': 'someOtherStringId',
  },
  {$set: {'baz.$.boolean': false}},
  {returnOriginal: false},
  callback
)

After some investigation, it turned out that $in seems to be the root cause of the issue. As I didn’t really needed that (usually there is only one element in the array), I’ve replaced it with $elemMatch - and the document is now updated successfully.

collection.findOneAndUpdate
(
  {
    foo: {$elemMatch: {$eq: 'bar'}},
    _id: 'someStringId',
    'baz._id': 'someOtherStringId',
  },
  {$set: {'baz.$.boolean': false}},
  {returnOriginal: false},
  callback
)

I’d like to understand the root cause of the issue, so feel free to chip in if you have a sensible explanation.

Please note that the server version is 3.0.15 and I’m using the official NodeJS driver (version 3.3.2).

Cheers

Hey @aberenyi

I am just curious on the use case you have where the _id is not sufficient to query the document.

And are you getting any error? Or just nModified: 0?

I do not think $set can use $ in the field position. See the docs
I believe that is for $ operator is for updating arrays.

And maybe the query is too specific if you are receiving nModified: 0 with no error.

Hey @Natac13

The use case covers finding a document and updating a particular array element within the doc identified by an id.

No error whatsoever, just nModified: 0 as you say, so I guess it could be too specific and mongo cannot figure out the array index.

$ works fine in $set if there is no $in in the query or it is replaced w/ $elemMatch.

1 Like

Oh I see.

Are you passing in string version of the _ids?
Maybe try to convert to MongoID Type

I do not think Mongo should have no problem finding the _id in an array.

Thank you for correcting me. I think it works when you remove the $in as you are no longer targeting to different arrays in the query and the $ is not getting ‘confused’ on which one it should represent.

If foo is a field of type array, then this will work too:
{ foo : 'bar' }
instead of
{ foo: { $elemMatch: { $eq: 'bar' } }

1 Like

The _ids are strings in this case, so that should not be an issue.

That was the only answer I could come up with that vaguely make sense, however, the query is not that complex, and I think the use case is valid.

I usually hate when someone says this, but this exact same query was working fine for at least 12 months, so maybe it’s the server version (the provider upgraded from 2.6 to 3.0 a while back) or the client lib (back in the day I’ve used findAndModify) that’s causing the turmoil.

Anyways, thanks for your insight @Natac13.