How to build a dynamic query with mongoengine
An example of the use of the Q class to build the query.
An input from a frontend:
query_input = [
[
{
"field": "some_field",
"operator": "gt",
"value": 30
},
{
"field": "some_field",
"operator": "lt",
"value": 40
},
{
"field": "some_field",
"operator": "",
"value": 35
}
],
[
{
"field": "another_field",
"operator": "istartswith",
"value": "test"
}
]
]
Assume that the first-level arrays should be join by AND and the dicts in the second-level arrays should be joined by OR. The solution may look like:
import json
from functools import reduce
from mongoengine import Q
def prepare_condition(condition):
field = [condition['field'], condition['operator']]
field = (s for s in field if s)
field = '__'.join(field)
return {field: condition['value']}
def prepare_conditions(row):
return (Q(**prepare_condition(condition)) for condition in row)
def join_conditions(row):
return reduce(lambda a, b: a | b, prepare_conditions(row))
def join_rows(rows):
return reduce(lambda a, b: a & b, rows)
query = join_rows(join_conditions(row) for row in query_input)
print(json.dumps(query.to_query(None), indent=4))
The output will be:
{
"$and": [
{
"$or": [
{
"some_field": {
"$gt": 30
}
},
{
"some_field": {
"$lt": 40
}
},
{
"some_field": 35
}
]
},
{
"another_field": "test"
}
]
}