Support $not in document match negation

XMLWordPrintableJSON

    • Type: Improvement
    • Resolution: Done
    • Priority: Minor - P4
    • None
    • Affects Version/s: None
    • Component/s: Index Maintenance, Querying
    • None
    • None
    • 3
    • None
    • None
    • None
    • None
    • None
    • None

      Given the example of a set of documents like this:

      Unable to find source-code formatter for language: javascript. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
      { "status" : "A", "type" : "C" }
      { "status" : "A", "type" : "D" }
      { "status" : "B", "type" : "C" }
      { "status" : "B", "type" : "D" }
      
      

      Currently if you wanted to find all documents that did not contain the combination of "status": "A" and "type": "C" you would have to resort to JavaScript evaluation.

      Unable to find source-code formatter for language: javascript. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
          db.collection.find(function() {
              !( this.status == "A" && this.type == "C")        
          })
      

      The aggregation pipeline allows such casting to a projection of a field:

      Unable to find source-code formatter for language: javascript. Available languages are: actionscript, ada, applescript, bash, c, c#, c++, cpp, css, erlang, go, groovy, haskell, html, java, javascript, js, json, lua, none, nyan, objc, perl, php, python, r, rainbow, ruby, scala, sh, sql, swift, visualbasic, xml, yaml
          db.collection.aggregate([
              { "$project": {
                  "status": 1,
                  "type": 1,
                  "unmatched": {
                      "$not": {
                          "$and": [
                              { "$eq": [ "$status", "A" ] },
                              { "$eq": [ "$type", "C" ] }
                          ]
                      }
                  }
              }},
              { "$match": {
                  "unmatched": false
              }}
          ])
      {code:javascript}
      
      But as there is not a native form of this for a query you could not filter for a $match stage.
      
      The seemingly natural form would be the similar:
      
      {code: javascript}
      
          db.collection.find({ "$not": { "status": "A", "type": "C" } })
      
      

      Where the existing $not operator applied it's left side evaluation to the query match negating the whole expression of the query on the right side.

      Not sure if there is an efficient way to apply this to index values or whether the result would be the same collection scan for all documents not matching the exclusion.

      The general problem presently being that $not is not allowed as a top level operator here at the moment and cannot reverse the entire query condition as it expects a left side field value. And the JavaScript form for a $where clause is not allowed within an aggregation expression

      error: {
              "$err" : "Can't canonicalize query: BadValue unknown top level operator: $not",
              "code" : 17287
      }
      

            Assignee:
            Unassigned
            Reporter:
            Neil Lunn
            Votes:
            0 Vote for this issue
            Watchers:
            7 Start watching this issue

              Created:
              Updated:
              Resolved: