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

$type not applied to nested elements of specific (dot notation) first-level array element

    • Type: Icon: Bug Bug
    • Resolution: Done
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: 2.5.5
    • Component/s: Querying
    • Environment:
    • Query
    • ALL
    • Hide
      db.test1.insert(
          { a : [ ["aa", "ab", "ac" ], [10, 11, 12] ]}
      );
      db.test1.insert(
          { a : [ ["ba", "bb", "bc" ], [20, 21, 22] ]}
      );
      db.test1.insert(
          { a : [ ["ca", "cb", "cc" ], [30, 31, 32] ]}
      );
      

      The query:

      > db.test1.find({ "a.0" : { "$type" : 2}})
      > db.test1.find({ "a.1" : { "$type" : 1}})
      > db.test1.find({ "a" : {"$elemMatch" : { "0" : {"$type" : 2}}}})
      { "_id" : ObjectId("5301dd9721e397fc8e5b537c"), "a" : [  [  "aa",  "ab",  "ac" ],  [  10,  11,  12 ] ] }
      { "_id" : ObjectId("5301dd9721e397fc8e5b537d"), "a" : [  [  "ba",  "bb",  "bc" ],  [  20,  21,  22 ] ] }
      { "_id" : ObjectId("5301dd9721e397fc8e5b537e"), "a" : [  [  "ca",  "cb",  "cc" ],  [  30,  31,  32 ] ] }
      > db.test1.find({ "a" : {"$elemMatch" : { "1" : {"$type" : 1}}}})
      { "_id" : ObjectId("5301dd9721e397fc8e5b537c"), "a" : [  [  "aa",  "ab",  "ac" ],  [  10,  11,  12 ] ] }
      { "_id" : ObjectId("5301dd9721e397fc8e5b537d"), "a" : [  [  "ba",  "bb",  "bc" ],  [  20,  21,  22 ] ] }
      { "_id" : ObjectId("5301dd9721e397fc8e5b537e"), "a" : [  [  "ca",  "cb",  "cc" ],  [  30,  31,  32 ] ] }
      >
      
      Show
      db.test1.insert( { a : [ [ "aa" , "ab" , "ac" ], [10, 11, 12] ]} ); db.test1.insert( { a : [ [ "ba" , "bb" , "bc" ], [20, 21, 22] ]} ); db.test1.insert( { a : [ [ "ca" , "cb" , "cc" ], [30, 31, 32] ]} ); The query: > db.test1.find({ "a.0" : { "$type" : 2}}) > db.test1.find({ "a.1" : { "$type" : 1}}) > db.test1.find({ "a" : { "$elemMatch" : { "0" : { "$type" : 2}}}}) { "_id" : ObjectId( "5301dd9721e397fc8e5b537c" ), "a" : [ [ "aa" , "ab" , "ac" ], [ 10, 11, 12 ] ] } { "_id" : ObjectId( "5301dd9721e397fc8e5b537d" ), "a" : [ [ "ba" , "bb" , "bc" ], [ 20, 21, 22 ] ] } { "_id" : ObjectId( "5301dd9721e397fc8e5b537e" ), "a" : [ [ "ca" , "cb" , "cc" ], [ 30, 31, 32 ] ] } > db.test1.find({ "a" : { "$elemMatch" : { "1" : { "$type" : 1}}}}) { "_id" : ObjectId( "5301dd9721e397fc8e5b537c" ), "a" : [ [ "aa" , "ab" , "ac" ], [ 10, 11, 12 ] ] } { "_id" : ObjectId( "5301dd9721e397fc8e5b537d" ), "a" : [ [ "ba" , "bb" , "bc" ], [ 20, 21, 22 ] ] } { "_id" : ObjectId( "5301dd9721e397fc8e5b537e" ), "a" : [ [ "ca" , "cb" , "cc" ], [ 30, 31, 32 ] ] } >

      From the documentation of $type:

      If the field holds an array, the $type operator performs the type check against the array elements and not the field.

      Unfortunately, the $type operator does not seem to get properly applied if the field is itself a concretely named (dot notation) (first-level) array element.
      Consider these arrays:

      > db.test1.find()
      { "_id" : ObjectId("5301dd9721e397fc8e5b537c"), "a" : [  [  "aa",  "ab",  "ac" ],  [  10,  11,  12 ] ] }
      { "_id" : ObjectId("5301dd9721e397fc8e5b537d"), "a" : [  [  "ba",  "bb",  "bc" ],  [  20,  21,  22 ] ] }
      { "_id" : ObjectId("5301dd9721e397fc8e5b537e"), "a" : [  [  "ca",  "cb",  "cc" ],  [  30,  31,  32 ] ] }
      >
      

      Suppose one now wanted to find those documents where the specific first-level element a.0 is itself an array and contains String elements:

      > db.test1.find({ "a.0" : { "$type" : 2}})
      > 
      

      Nothing comes up even though a.0 contains String elements in all documents.

      Note that trying to achieve this via the $elemMatch route does work:

      > db.test1.find({ "a" : {"$elemMatch" : { "0" : {"$type" : 2}}}})
      { "_id" : ObjectId("5301dd9721e397fc8e5b537c"), "a" : [  [  "aa",  "ab",  "ac" ],  [  10,  11,  12 ] ] }
      { "_id" : ObjectId("5301dd9721e397fc8e5b537d"), "a" : [  [  "ba",  "bb",  "bc" ],  [  20,  21,  22 ] ] }
      { "_id" : ObjectId("5301dd9721e397fc8e5b537e"), "a" : [  [  "ca",  "cb",  "cc" ],  [  30,  31,  32 ] ] }
      >
      

      However, it seems rather inefficient to first apply a check for a "field" 0 on potentially all array elements of a when one already knows the concrete element to investigate.

      (On a side note, I have always found it rather peculiar that $type is applied to the elements of an array field rather than to the field itself when {"$elemMatch" : {"$type" : <id>}} already captures these desired semantics)

      This seems somewhat related to SERVER-11455.

            Assignee:
            backlog-server-query Backlog - Query Team (Inactive)
            Reporter:
            tomzahn Thomas Zahn
            Votes:
            2 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: