FindOne with OR matching wrong data

I have a findOne running this query:

const blockCheck = await ctx.db.collection("userblocks").findOne({
    $or: [
      { user: ctx.state.user.id, blocked: ctx.state.comment.forAuthor },
      { user: ctx.state.comment.forAuthor, blocked: ctx.state.user.id }
    ]
  }, { session })

The issue i’m having is that for one user, when the user ID and the author ID are the same, this OR query returns a block that doesn’t match the query. I can replicate it with this user every single time. I can’t yet replicate it with any other user. I’m concerned there are more users experiencing this random behavior that I can’t yet see.

Does anyone have any idea why this would be happening? It shouldn’t be.

For example, if I run this in MongoDB Compass:

{ $or: [
  { 
    user: ObjectId('6111111af44c3438499b00a0'),
    blocked: ObjectId('6111111af44c3438499b00a0')
  },
  {
    user: ObjectId('6111111af44c3438499b00a0'),
    blocked: ObjectId('6111111af44c3438499b00a0')
  }
] }

It returns 0 results as expected, for the given user that has the issue when the first code example is run against them and a document is returned. I also had them test by removing all their blocks, and 0 results were returned as expected, when they added them back and created new documents in the collection, this issue started happening again.

For further clarification, it returns this object when running the findOne:

{
  _id: new ObjectId("64fc57379b5ad000ffde000"),
  user: new ObjectId("6111111af44c3438499b00a0"),
  blocked: new ObjectId("65cade111531f6bc014dbb45"),
  createdAt: 2023-09-09T11:29:59.984Z,
  notes: null
}

I’m running on MongoDB Atlas on v7.0.1 in a 3 node replica set.

The query seems correct and works correctly.

However, I have notice that

is not a valid ObjectId since I get the error

Argument passed in must be a string of 12 bytes or a string of 24 hex characters or an integer.

What I think is that you have redacted your problem in order to simplify it. But it was over-simplified and the real issue is now hidden. What I suspect is that your fields user and blocked and inside an array rather than at the top level. You have indeed have an array you will need to use $elemMatch like:

 $or: [
      { "$elemMatch" : { "array.user" : ctx.state.user.id, "array.blocked" : ctx.state.comment.forAuthor },
      { "$elemMatch" : { "array.user" : ctx.state.comment.forAuthor, "array.blocked": ctx.state.user.id }
    ]