Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-73697

Do not split out match expression on meta field when it's not renameable

    • Type: Icon: Bug Bug
    • Resolution: Fixed
    • Priority: Icon: Critical - P2 Critical - P2
    • 7.0.0-rc0, 6.0.5, 6.3.0-rc1
    • Affects Version/s: 6.0.4, 6.3.0-rc0, 6.2.0-rc6
    • Component/s: None
    • None
    • Fully Compatible
    • ALL
    • v6.3, v6.0
    • Hide
      // $size issue repro
      db.createCollection("ts", {timeseries: {timeField: "time", metaField: "tag"}});
      db.ts.insert({time: ISODate(), tag: {a: [1, 2]}, f: 1});
      db.ts.insert({time: ISODate(), tag: {a: [1]}, f: 2});
      
      db.non_ts.insert({time: ISODate(), tag: {a: [1, 2]}, f: 1});
      db.non_ts.insert({time: ISODate(), tag: {a: [1]}, f: 2});
      
      db.ts.find({"tag.a": {$size: 1}});
      // no results
      db.ts.explain().find({"tag.a": {$size: 1}});
      // The wrong filter is pushed down to the COLLSCAN. "tag.a" should have been renamed as "meta.a"
      ...
      					"winningPlan" : {
      						"stage" : "COLLSCAN",
      						"filter" : {
      							"tag.a" : {
      								"$size" : 1
      							}
      						},
      						"direction" : "forward"
      					},
      ...
      db.ts.find({"tag.a": {$size: 2}});
      // no results
      db.ts.explain().find({"tag.a": {$size: 2}});
      // Same as above
      ...
      					"winningPlan" : {
      						"stage" : "COLLSCAN",
      						"filter" : {
      							"tag.a" : {
      								"$size" : 2
      							}
      						},
      						"direction" : "forward"
      					},
      ...
      db.non_ts.find({"tag.a": {$size: 1}});
      // { "_id" : ObjectId("63e1b2df7904f99bc29bd5d3"), "time" : ISODate("2023-02-07T02:09:35.334Z"),
      // "tag" : { "a" : [ 1 ] }, "f" : 2 }
      db.non_ts.find({"tag.a": {$size: 2}});
      // { "_id" : ObjectId("63e1b2de7904f99bc29bd5d1"), "time" : ISODate("2023-02-07T02:09:34.767Z"),
      // "tag" : { "a" : [ 1, 2 ] }, "f" : 1 }
      
      // $elemMatch issue repro
      > db.ts.find({"tag.a": {$elemMatch: {$gt: 1}}});
      // no results
      > db.ts.find({"tag.a": {$gt: 1}});
      { "time" : ISODate("2023-02-07T02:06:34.469Z"), "tag" : { "a" : [ 1, 2 ] }, "f" : 1, "_id" : ObjectId("63e1b22a7904f99bc29bd5cd") }
      > db.non_ts.find({"tag.a": {$gt: 1}});
      { "_id" : ObjectId("63e1c6edca1cee615824301b"), "time" : ISODate("2023-02-07T03:35:09.023Z"), "tag" : { "a" : [ 1, 2 ] }, "f" : 1 }
      > db.non_ts.find({"tag.a": {$elemMatch: {$gt: 1}}});
      { "_id" : ObjectId("63e1b2de7904f99bc29bd5d1"), "time" : ISODate("2023-02-07T02:09:34.767Z"), "tag" : { "a" : [ 1, 2 ] }, "f" : 1 }
      
      Show
      // $size issue repro db.createCollection( "ts" , {timeseries: {timeField: "time" , metaField: "tag" }}); db.ts.insert({time: ISODate(), tag: {a: [1, 2]}, f: 1}); db.ts.insert({time: ISODate(), tag: {a: [1]}, f: 2}); db.non_ts.insert({time: ISODate(), tag: {a: [1, 2]}, f: 1}); db.non_ts.insert({time: ISODate(), tag: {a: [1]}, f: 2}); db.ts.find({ "tag.a" : {$size: 1}}); // no results db.ts.explain().find({ "tag.a" : {$size: 1}}); // The wrong filter is pushed down to the COLLSCAN. "tag.a" should have been renamed as "meta.a" ... "winningPlan" : { "stage" : "COLLSCAN" , "filter" : { "tag.a" : { "$size" : 1 } }, "direction" : "forward" }, ... db.ts.find({ "tag.a" : {$size: 2}}); // no results db.ts.explain().find({ "tag.a" : {$size: 2}}); // Same as above ... "winningPlan" : { "stage" : "COLLSCAN" , "filter" : { "tag.a" : { "$size" : 2 } }, "direction" : "forward" }, ... db.non_ts.find({ "tag.a" : {$size: 1}}); // { "_id" : ObjectId( "63e1b2df7904f99bc29bd5d3" ), "time" : ISODate( "2023-02-07T02:09:35.334Z" ), // "tag" : { "a" : [ 1 ] }, "f" : 2 } db.non_ts.find({ "tag.a" : {$size: 2}}); // { "_id" : ObjectId( "63e1b2de7904f99bc29bd5d1" ), "time" : ISODate( "2023-02-07T02:09:34.767Z" ), // "tag" : { "a" : [ 1, 2 ] }, "f" : 1 } // $elemMatch issue repro > db.ts.find({ "tag.a" : {$elemMatch: {$gt: 1}}}); // no results > db.ts.find({ "tag.a" : {$gt: 1}}); { "time" : ISODate( "2023-02-07T02:06:34.469Z" ), "tag" : { "a" : [ 1, 2 ] }, "f" : 1, "_id" : ObjectId( "63e1b22a7904f99bc29bd5cd" ) } > db.non_ts.find({ "tag.a" : {$gt: 1}}); { "_id" : ObjectId( "63e1c6edca1cee615824301b" ), "time" : ISODate( "2023-02-07T03:35:09.023Z" ), "tag" : { "a" : [ 1, 2 ] }, "f" : 1 } > db.non_ts.find({ "tag.a" : {$elemMatch: {$gt: 1}}}); { "_id" : ObjectId( "63e1b2de7904f99bc29bd5d1" ), "time" : ISODate( "2023-02-07T02:09:34.767Z" ), "tag" : { "a" : [ 1, 2 ] }, "f" : 1 }
    • QE 2023-02-20

      The array match expressions such as $elemMatch and $size are not properly pushed down to the timeseries system.buckets collection.

      I strongly suspect that this is because $elemMatch & $size are array match expressions and splitMatchExpressionBy() function supports only renameable match expressions but the array match expressions are not categorized as "renameable" by hasOnlyRenameableMatchExpressionChildren(). I don't know why splitMatchExpressionBy() supports only renameable match expressions.

      Note that $jsonSchema-related internal match expressions are also not categorized as "renameable" and I expect that the same issues exists for $jsonSchema expression(s).

      Some of $jsonSchema-related internal match expressions will be supported by SERVER-73535.

            Assignee:
            yoonsoo.kim@mongodb.com Yoon Soo Kim
            Reporter:
            yoonsoo.kim@mongodb.com Yoon Soo Kim
            Votes:
            0 Vote for this issue
            Watchers:
            12 Start watching this issue

              Created:
              Updated:
              Resolved: