Core Server
  1. Core Server
  2. SERVER-1248

Should have an $* array-key-wildcard operator

    Details

    • Type: Improvement Improvement
    • Status: Closed Closed
    • Priority: Major - P3 Major - P3
    • Resolution: Duplicate
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: None
    • Labels:
      None
    • Backport:
      No
    • # Replies:
      9
    • Last comment by Customer:
      false

      Description

      As far as I can tell there is no way to find an object containing a value in a subarray if you do not know the exact array-key path, so if the following were a collection of orders you cannot find all orders by unit ID without modifying the schema:

      array(
      '_id' => 213,
      'units' = array(
      0 => array('id' => 5, 'color' => 'red'),
      1 => array('id' => 3, 'color' => 'blue'),
      2 => array('id' => 8, 'color' => 'polka dot'),
      3 => array('id' => 9, 'color' => 'green')
      )
      );

      array(
      '_id' => 456,
      'units' = array(
      0 => array('id' => 8, 'color' => 'purple'),
      1 => array('id' => 2, 'color' => 'yellow')
      )
      );

      We should be able to do something like:

      $find = array('units.$*.id' => 8);
      $col->find($find);

      Assuming $* would be a wildcard operator that covers any key within the array

        Issue Links

          Activity

          Hide
          Karoly Negyesi
          added a comment -

          just query on units.id , it works, and don't forget $elemMatch if you are querying on two.

          Show
          Karoly Negyesi
          added a comment - just query on units.id , it works, and don't forget $elemMatch if you are querying on two.
          Hide
          phpMoAdmin
          added a comment -

          Karoly, you are in-fact correct for the example that I posted, but the issue still exists for an array without any identifiable subkey.

          In the next schema example, how would you search for a document with the "blueScarf.jpg" image if the arraykey is an unknown timestamp?

          [_id] => 1
          [img] => Array (
          [1276297762] => greenPlant.jpg
          )

          [_id] => 2
          [img] => Array (
          [1276291209] => redScarf.jpg
          [1276299876] => blueScarf.jpg
          )

          [_id] => 3
          [img] => Array (
          [1276290193] => purpleCar.jpg
          [1276299233] => yellowCar.jpg
          [1276290971] => whiteCar.jpg
          )

          Show
          phpMoAdmin
          added a comment - Karoly, you are in-fact correct for the example that I posted, but the issue still exists for an array without any identifiable subkey. In the next schema example, how would you search for a document with the "blueScarf.jpg" image if the arraykey is an unknown timestamp? [_id] => 1 [img] => Array ( [1276297762] => greenPlant.jpg ) [_id] => 2 [img] => Array ( [1276291209] => redScarf.jpg [1276299876] => blueScarf.jpg ) [_id] => 3 [img] => Array ( [1276290193] => purpleCar.jpg [1276299233] => yellowCar.jpg [1276290971] => whiteCar.jpg )
          Hide
          John Crenshaw
          added a comment -

          I sort of expected to be able to do something similar, except I expected to be able to use the $ operator here. I.E. units.$.id.

          In some respects, this is less of a request for new functionality, and more of a request for a more logical and memorable syntax for querying arrays.

          If $elemMatch were enhanced to work with objects, the $ operator could be used as shorthand for $elemMatch, and would also work for objects (which is what you have in the timestamp case shown).

          Extending $elemMatch would additionally help alleviate some of the issues with arrays and PHP (it's too easy to accidentally break the numbering, resulting in an "object" being stored where an "array" is expected, and some operations stop working.) It appears that the discrepancy between "arrays" and "objects" (especially for PHP) may actually be at the root of this request, and blurring the lines so that it doesn't matter so much may fix the real need here.

          Show
          John Crenshaw
          added a comment - I sort of expected to be able to do something similar, except I expected to be able to use the $ operator here. I.E. units.$.id. In some respects, this is less of a request for new functionality, and more of a request for a more logical and memorable syntax for querying arrays. If $elemMatch were enhanced to work with objects, the $ operator could be used as shorthand for $elemMatch, and would also work for objects (which is what you have in the timestamp case shown). Extending $elemMatch would additionally help alleviate some of the issues with arrays and PHP (it's too easy to accidentally break the numbering, resulting in an "object" being stored where an "array" is expected, and some operations stop working.) It appears that the discrepancy between "arrays" and "objects" (especially for PHP) may actually be at the root of this request, and blurring the lines so that it doesn't matter so much may fix the real need here.
          Hide
          Benjamin Menküc
          added a comment -

          I have a similar problem.
          My database looks like
          {
          "log": {
          "0": {
          "msg":

          { "text": "text1)" }


          },
          "1": {
          "msg":

          { "text": "text2" }


          }
          }

          I want to make a query on "text" for every msg in the array by using regexps (i need it that way). I tried:
          find({$where:"/^text/.test(this.log.msg.text)"})
          which doesnt work.
          Is there any solution for this?
          BTW: this was tested using the mongoconsole front-end.

          regards,
          Benjamin

          Show
          Benjamin Menküc
          added a comment - I have a similar problem. My database looks like { "log": { "0": { "msg": { "text": "text1)" } }, "1": { "msg": { "text": "text2" } } } I want to make a query on "text" for every msg in the array by using regexps (i need it that way). I tried: find({$where:"/^text/.test(this.log.msg.text)"}) which doesnt work. Is there any solution for this? BTW: this was tested using the mongoconsole front-end. regards, Benjamin
          Hide
          phpMoAdmin
          added a comment -

          Hi Benjamin,

          If your subkeys are consistent (they are always "text") then you can just skip the definition of the preceding variable-keys:

          find(

          { "log.msg.text": ........ }

          The issue in this ticket only applies if your subkey's vary and cannot be defined in the query.

          Show
          phpMoAdmin
          added a comment - Hi Benjamin, If your subkeys are consistent (they are always "text") then you can just skip the definition of the preceding variable-keys: find( { "log.msg.text": ........ } The issue in this ticket only applies if your subkey's vary and cannot be defined in the query.
          Hide
          Justin Shanks
          added a comment - - edited

          For my example, our objects in our content collection look like this:
          _id: 12345678,
          channels: {
          print_issue: {
          string_identifierA:

          { channel: 'MAR11', section: 'new_products', ... }

          ,
          string_identifierB:

          { channel: 'APR11', section: 'new_products', ... }

          }
          }

          I would like to query it like this

          db.content.find(

          {'channels.print_issue.$.channel': 'MAR11'}

          );

          I do realize if I took the 'string_identifier' out as the key of the object, put it into the sub object, and changed 'print_issue' to a normal array, that I could do a query like this:

          db.content.find(

          {'channels.print_issue.channel': 'MAR11'}

          );

          But I'd prefer to not modify my object format just for mongo inserts since the object format is used in the same way over multiple applications/api's as I'm sure is the case for many people who want or expect this functionality when considering mongo.

          Show
          Justin Shanks
          added a comment - - edited For my example, our objects in our content collection look like this: _id: 12345678, channels: { print_issue: { string_identifierA: { channel: 'MAR11', section: 'new_products', ... } , string_identifierB: { channel: 'APR11', section: 'new_products', ... } } } I would like to query it like this db.content.find( {'channels.print_issue.$.channel': 'MAR11'} ); I do realize if I took the 'string_identifier' out as the key of the object, put it into the sub object, and changed 'print_issue' to a normal array, that I could do a query like this: db.content.find( {'channels.print_issue.channel': 'MAR11'} ); But I'd prefer to not modify my object format just for mongo inserts since the object format is used in the same way over multiple applications/api's as I'm sure is the case for many people who want or expect this functionality when considering mongo.
          Hide
          Szabolcs Szász
          added a comment -

          Yet another use case (a taxonomy "poly-tree").

          Currently it's implemented as:

          taxon:

          { 'parent': 'taxon0' }

          // when all sources agree
          or
          taxon: { 'parent':

          { 'source1': 'taxon1', 'source2': 'taxon2' }

          } // when sources disagree

          But, alas, I can't seem to just get 'taxon1' and/or 'taxon2' regardless of source (1 or 2) in MongoDB.

          Instead, I fear I might need to change the data model to:

          taxon: { 'parent' {

          { 'source': 'source1', 'parent' => 'taxon1' }

          ,

          { 'source': 'source2', 'parent' => 'taxon2' }

          }
          }

          which would not only be less sexy, but would mean lots of code changes, too, and would also put MongoDB to the "syntactic bottleneck" role instead of PHP.

          Show
          Szabolcs Szász
          added a comment - Yet another use case (a taxonomy "poly-tree"). Currently it's implemented as: taxon: { 'parent': 'taxon0' } // when all sources agree or taxon: { 'parent': { 'source1': 'taxon1', 'source2': 'taxon2' } } // when sources disagree But, alas, I can't seem to just get 'taxon1' and/or 'taxon2' regardless of source (1 or 2) in MongoDB. Instead, I fear I might need to change the data model to: taxon: { 'parent' { { 'source': 'source1', 'parent' => 'taxon1' } , { 'source': 'source2', 'parent' => 'taxon2' } } } which would not only be less sexy, but would mean lots of code changes, too, and would also put MongoDB to the "syntactic bottleneck" role instead of PHP.
          Hide
          Glenn Maynard
          added a comment -

          This is really requesting a feature for searching documents and doesn't have anything to do with arrays. I think the OP was confused because PHP conflates key/value dictionaries and arrays, which is confusing for people whose first language is PHP.

          This has parallels with multikey searching for arrays.

          See also SERVER-5463.

          Show
          Glenn Maynard
          added a comment - This is really requesting a feature for searching documents and doesn't have anything to do with arrays. I think the OP was confused because PHP conflates key/value dictionaries and arrays, which is confusing for people whose first language is PHP. This has parallels with multikey searching for arrays. See also SERVER-5463 .
          Hide
          Scott Hernandez
          added a comment -

          This seems to be a dup of SERVER-267. Please let us know otherwise.

          Show
          Scott Hernandez
          added a comment - This seems to be a dup of SERVER-267 . Please let us know otherwise.

            People

            • Votes:
              9 Vote for this issue
              Watchers:
              10 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Days since reply:
                1 year, 29 weeks, 3 days ago
                Date of 1st Reply: