Search code examples
mongodbpymongo

PyMongo: querying using json with a list


If I have some json like this:

query = {
   "canonical.operatingSystemFamily": "Linux",
   "canonical.region": "us-east-1"
}

I can pass that directly into find and it works:

self._db_conn[collection_name].find(query)

I want to do the same, but with lists, e.g.:

query = {
    "canonical.operatingSystemFamily": ["Linux","Windows"],
    "canonical.region": ["us-east-1", "us-east-2"]
}

Is there a way to do that? I know about "$in" but I do not want to have to parse my query data. This is a very simplified example, and there are a lot of fields that may or may not be there. Is there a way to use that json with lists directly?


Solution

  • It's not much of a parser - just checking type.

    $ ipython
    Python 3.8.10 (default, May  4 2021, 00:00:00) 
    Type 'copyright', 'credits' or 'license' for more information
    IPython 8.1.0 -- An enhanced Interactive Python. Type '?' for help.
    
    In [1]: query = {
       ...:     "canonical.operatingSystemFamily": ["Linux","Windows"],
       ...:     "canonical.region": ["us-east-1", "us-east-2"]
       ...: }
    
    In [2]: for k,v in query.items():
       ...:     if type(v)==list:
       ...:         query[k]={"$in": v}
       ...: 
    
    In [3]: query
    Out[3]: 
    {'canonical.operatingSystemFamily': {'$in': ['Linux', 'Windows']},
     'canonical.region': {'$in': ['us-east-1', 'us-east-2']}}
    

    If you wanted, you could define a function to transform query when a list is present.

    from copy import deepcopy
    def query_lfixer(query, copy=True):
        if copy:
            query = deepcopy(query)
        for k, v in query.items():
            if type(v)==list:
                query[k] = {"$in": v}
        return query
    

    And then you could use it like:

    self._db_conn[collection_name].find(query_lfixer(query))
    

    Or you could transform query in any number of other ways too.