Express write path tasserts on _id $eq with DBRef-shaped object

    • Type: Bug
    • Resolution: Unresolved
    • Priority: Major - P3
    • None
    • Affects Version/s: None
    • Component/s: None
    • Query Optimization
    • ALL
    • Hide
      const conn = MongoRunner.runMongod({});
      const db = conn.getDB(jsTestName());
      const coll = db.bug;
      
      try {
          assert.commandWorked(coll.insertOne({_id: 1}));
      
          // WILL FAIL: 9248801 "Expected the input to be of the shape {_id: <value>}, but the input is { _id: { $ref: \"foo\", $id: 1.0 } }"
          assert.commandWorked(
              db.runCommand({
                  update: coll.getName(),
                  updates: [{q: {_id: {$eq: {$ref: "foo", $id: 1}}}, u: {$set: {x: 1}}}],
              }),
          );
      } finally {
          MongoRunner.stopMongod(conn);
      }
       
      Show
      const conn = MongoRunner.runMongod({}); const db = conn.getDB(jsTestName()); const coll = db.bug; try {     assert .commandWorked(coll.insertOne({_id: 1})); // WILL FAIL: 9248801 "Expected the input to be of the shape {_id: <value>}, but the input is { _id: { $ref: \" foo\ ", $id: 1.0 } }"     assert .commandWorked(         db.runCommand({             update: coll.getName(),             updates: [{q: {_id: {$eq: {$ref: "foo" , $id: 1}}}, u: {$set: {x: 1}}}],         }),     ); } finally {     MongoRunner.stopMongod(conn); }
    • None
    • None
    • None
    • None
    • None
    • None
    • None

      Problem

      The Express update/delete fast path can tassert for an exact _id equality query where the explicit $eq value is an object whose first field starts with $, such as a DBRef-shaped object.

      Reproduction

      db.bug.insertOne({_id: 1});
      
      db.runCommand({
        update: "bug",
        updates: [{q: {_id: {$eq: {$ref: "foo", $id: 1}}}, u: {$set: {x: 1}}}]
      });
      

      The request is routed to the Express write path and mongod hits a tassert:

      • update: tassert(9248801)
      • delete: tassert(9248804)

      Root Cause

      isSimpleIdQuery() accepts _id: {$eq: <object>} as an exact _id query. The Express write path then unwraps $eq to _id: <object>, but re-validates the unwrapped query with isExactMatchOnId(), which rejects object values whose first field starts with $. This incorrectly treats a literal DBRef-shaped value as operator-like syntax.

            Assignee:
            Unassigned
            Reporter:
            Max Verbinnen
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated: