Query using $or and $ne on sharded collection can include orphan documents

    • Type: Bug
    • Resolution: Unresolved
    • Priority: Major - P3
    • None
    • Affects Version/s: None
    • Component/s: None
    • Query Optimization
    • ALL
    • Hide
      import {ShardingTest} from "jstests/libs/shardingtest.js";
      
      const docs = [
          {_id: 0, t: 6, m: NumberInt(0)},
          {_id: 1, t: 0, m: NumberInt(0)}
      ];
      const query = [
          {$project: {a: "$t"}},
          {$match: {$or: [{a: 6, m: {$ne: 1}}]}}
      ];
      
      const st = new ShardingTest({shards: 2, mongos: 1});
      const shardedDb = st.getDB("test");
      assert(st.adminCommand({enablesharding: "test", primaryShard: st.shard0.shardName}));
      
      const coll = shardedDb.coll;
      assert(coll.drop());
      assert.commandWorked(coll.insert(docs));
      assert.commandWorked(coll.createIndex({t: 1}));
      
      const resultsBeforeSharding = coll.aggregate(query).toArray()
      jsTestLog('results before sharding');
      jsTestLog(resultsBeforeSharding);
      // [ { "_id" : 0, "a" : 6 } ]
      
      assert(st.adminCommand({shardcollection: `test.coll`, key: {t: 1}}));
      // One doc on each shard
      assert(st.adminCommand({split: `test.coll`, middle: {t: 3}}));
      // shard0 has the t=0 doc, shard1 has the t=6 doc
      assert(st.adminCommand({moveChunk: `test.coll`, find: {t: 6}, to: st.shard1.shardName}))
      
      jsTestLog(st.getDB("admin").aggregate([{$shardedDataDistribution: {}}]).toArray())
      // One orphan doc exists on shard0
      
      const resultsAfterSharding = coll.aggregate(query).toArray();
      jsTestLog('results after sharding')
      jsTestLog(resultsAfterSharding);
      // [ { "_id" : 0, "a" : 6 }, { "_id" : 0, "a" : 6 } ]
      jsTestLog(coll.explain().aggregate(query));
      // no shard filter stage
      
      assert.eq(resultsBeforeSharding, resultsAfterSharding, {resultsBeforeSharding, resultsAfterSharding})
      
      st.stop();
      
      Show
      import {ShardingTest} from "jstests/libs/shardingtest.js" ; const docs = [ {_id: 0, t: 6, m: NumberInt(0)}, {_id: 1, t: 0, m: NumberInt(0)} ]; const query = [ {$project: {a: "$t" }}, {$match: {$or: [{a: 6, m: {$ne: 1}}]}} ]; const st = new ShardingTest({shards: 2, mongos: 1}); const shardedDb = st.getDB( "test" ); assert (st.adminCommand({enablesharding: "test" , primaryShard: st.shard0.shardName})); const coll = shardedDb.coll; assert (coll.drop()); assert .commandWorked(coll.insert(docs)); assert .commandWorked(coll.createIndex({t: 1})); const resultsBeforeSharding = coll.aggregate(query).toArray() jsTestLog( 'results before sharding' ); jsTestLog(resultsBeforeSharding); // [ { "_id" : 0, "a" : 6 } ] assert (st.adminCommand({shardcollection: `test.coll`, key: {t: 1}})); // One doc on each shard assert (st.adminCommand({split: `test.coll`, middle: {t: 3}})); // shard0 has the t=0 doc, shard1 has the t=6 doc assert (st.adminCommand({moveChunk: `test.coll`, find: {t: 6}, to: st.shard1.shardName})) jsTestLog(st.getDB( "admin" ).aggregate([{$shardedDataDistribution: {}}]).toArray()) // One orphan doc exists on shard0 const resultsAfterSharding = coll.aggregate(query).toArray(); jsTestLog( 'results after sharding' ) jsTestLog(resultsAfterSharding); // [ { "_id" : 0, "a" : 6 }, { "_id" : 0, "a" : 6 } ] jsTestLog(coll.explain().aggregate(query)); // no shard filter stage assert .eq(resultsBeforeSharding, resultsAfterSharding, {resultsBeforeSharding, resultsAfterSharding}) st.stop();
    • None
    • 3
    • TBD
    • None
    • None
    • None
    • None
    • None
    • None

      In the repro attached, we insert two documents into a collection and then shard the collection. Then we move a chunk so that each shard owns a document, but one shard has an orphaned document.

      After running the query in the repro, we see a document appear twice, because the query does not have a shard filter stage so the orphaned document is included in the results.

            Assignee:
            Unassigned
            Reporter:
            Matt Boros
            Votes:
            0 Vote for this issue
            Watchers:
            9 Start watching this issue

              Created:
              Updated: