databasemongodbdictionaryconditional-statementspymongo

How to use conditional statements in Pymongo find method


So I am trying to search through my database to see which documents passed a particular test. The structure of the dictionary is

dict = {
       'test_results':{
                        'test1':1, ## either 0 or 1 depending on failing/passing respectively 
                        'test2':0,
                        ...,
                        'testN':1
        },
       'identifier': ID 
}

So I want to do a search to print all the identifiers of documents that failed test 2.

I tried writing a query such as

list(mycol.find({},{
    "_id":0,
    "$expr":{
        "$cond": {
            'if': {"$lt":["$test_results.test2",1]},
            'then': {"ID":"$identifier"}
        }
    }
}))

I expected this to give me the identifiers of the documents where test 2 resulted in 0, however this just gives me the error

FieldPath field names may not start with '$'. Consider using $getField or $setField., full error: {'ok': 0.0, 'errmsg': "FieldPath field names may not start with '$'. Consider using $getField or $setField.", 'code': 16410, 'codeName': 'Location16410'}

I was wondering what did I do wrong with my query/any suggestions to make my search more efficient.


Solution

  • That second parameter to find is a projection, so it must have field names at the top level. You've put $expr but you probably wanted ID. So to fix your existing query with the least changes:

    list(mycol.find({},{
      "_id": 0,
      "ID": {
        "$cond": {
          "if": { "$lt": ["$test_results.test2", 1] },
          "then": "$identifier",
          "else": None
        }
      }
    }))
    

    JS equivalent in Mongo Plaground.

    But with that query you get None for those IDs where it passed; which is probably not useful. See the second document in the playground which has test2: 1 so the result has ID: null.

    However, you said "give me the identifiers of the documents where test 2 resulted in 0", so that should be part of your find criteria:

    list(mycol.find(
      { "test_results.test2": 0 },  # the query
      # the projection
      {
        "_id": 0,
        "ID": "$identifier"
      }
    ))
    

    As you can see, this is a far simpler query & projection. Mongo Playground

    And unless you have negative values which should be treated like 0, check for equality with 0 instead of "less than 1".