Reputation: 2271
I have a python dictionary like this
{'OR': [{'AND': [{'column': 'XXX', 'operator': '=', 'value': u'M'}, {'column': 'XXX', 'operator': '=', 'value': 'N'}]}, {'column': 'YYY', 'operator': '>=', 'value': '3.0'}]}
Now, i want to convert it to something like
{'$or': [{'$and': [{'XXX': 'M'}, {'YYY': 'N'}]}, {'YYY': {u'$gte': 3.0}}]}
Which is clearly the equivalent pymongo statement I believe.
the code I have written so far is like this :
FILTMAP = {'>=': '$gte', '<=': '$lte', '>': '$gt', '<': '$lt', "!=":"$ne"}
CONJUNCTION_MAP = {"AND":"$and", "OR":"$or"}
def gen_mongo_filters_json(filter, supplied_key="")
first_key = filters.keys()[0]
if first_key == 'OR' or first_key == 'AND':
if supplied_key == "":
return_dict[CONJUNCTION_MAP[first_key]] = []
else:
temp_dict[CONJUNCTION_MAP[first_key]] = []
#return_dict[supplied_key] = temp_dict
for i in range (len(filters[first_key])):
if supplied_key == "":
return_dict[CONJUNCTION_MAP[first_key]].append(gen_mongo_filters_json(filters[first_key][i], first_key))
else:
temp_dict[CONJUNCTION_MAP[first_key]].append(gen_mongo_filters_json(filters[first_key][i], first_key))
return_dict[CONJUNCTION_MAP[supplied_key]].append(temp_dict)
else:
operator = filters['operator']
if operator == "=":
ret_dict = {filters['column']:filters['value']
return ret_dict
else:
operator = FILTMAP[operator]
ret_dict = {filters['column']:{operator:filters['value']}}
return ret_dict
return return_dict
The output it generates is :
{u'$or': [{u'$and': [{u'Engine': u'MSN'}, {u'Engine': u'Google'}]}, {u'$and': [{u'Engine': u'MSN'}, {u'Engine': u'Google'}]}, {...}, {u'Imps': {u'$gte': 3.0}}]}
Which is near to the solution but not the exact one. It works fine for dictionaries like
{'AND': [{'column': 'XXX', 'operator': '=', 'value': 'M'}, {'column': 'XXX', 'operator': '=', 'value': 'N'}]}
OR
{'column': 'YYY', 'operator': '>', 'value': '1000'}
can you point to me a direction?
(the idea is to create a generic one. so, i would like to generate equivalent to any valid python dictionary into pymongo statement. the minimum is the last one)
Upvotes: 4
Views: 397
Reputation: 2271
Thanks for the answer. I have also figured out some thing also. here is the full code
FILTMAP = {'>=': '$gte', '<=': '$lte', '>': '$gt', '<': '$lt', "!=":"$ne"}
CONJUNCTION_MAP = {"AND":"$and", "OR":"$or"}
def gen_mongo_filters_json(filters, supplied_key=""):
return_dict = {}
temp_dict = {}
first_key = filters.keys()[0]
if first_key == 'OR' or first_key == 'AND':
if supplied_key == "":
return_dict[CONJUNCTION_MAP[first_key]] = []
else:
temp_dict[CONJUNCTION_MAP[first_key]] = []
#return_dict[supplied_key] = temp_dict"""
for i in range (len(filters[first_key])):
if supplied_key == "":
return_dict[CONJUNCTION_MAP[first_key]].append(gen_mongo_filters_json(filters[first_key][i], first_key))
else:
for i in range (len(filters[first_key])):
temp_dict[CONJUNCTION_MAP[first_key]].append(gen_mongo_filters_json(filters[first_key][i], first_key))
return temp_dict
else:
operator = filters['operator']
if operator == "=":
ret_dict = {filters['column']:filters['value']}
return ret_dict
else:
operator = FILTMAP[operator]
ret_dict = {filters['column']:{operator:filters['value']}}
return ret_dict
return return_dict
if __name__ == "__main__":
print gen_mongo_filters_json({'OR': [{'AND': [{'column': 'XXX', 'operator': '=', 'value': 'M'}, {'column': 'XXX', 'operator': '=', 'value': 'N'}]}, {'AND': [{'column': 'PPP', 'operator': '=', 'value': 'R'}, {'column': 'DDD', 'operator': '=', 'value': 'T'}]}]})
enter code here
Please let me know your reviews
i tried it for
{'column': 'YYY', 'operator': '>', 'value': '1000'}
{'AND': [{'column': 'XXX', 'operator': '=', 'value': 'M'}, {'column': 'XXX', 'operator': '=', 'value': 'N'}]}
{'OR': [{'AND': [{'column': 'XXX', 'operator': '=', 'value': u'M'}, {'column': 'XXX', 'operator': '=', 'value': 'N'}]}, {'column': 'YYY', 'operator': '>=', 'value': '3.0'}]}
{'OR': [{'AND': [{'column': 'XXX', 'operator': '=', 'value': u'M'}, {'column': 'XXX', 'operator': '=', 'value': 'N'}]}, {'AND': [{'column': 'PPP', 'operator': '=', 'value': u'R'}, {'column': 'DDD', 'operator': '=', 'value': 'T'}]}]}
and here are the outputs
{u'YYY': {u'$gt': u'1000'}}
{u'$and': [{u'XXX': u'M'}, {u'XXX': u'N'}]}
{u'$or': [{u'$and': [{u'XXX': u'M'}, {u'XXX': u'N'}]}, {u'YYY': {u'$gte': u'3.0'}}]}
{u'$or': [{u'$and': [{u'XXX': u'M'}, {u'XXX': u'N'}]}, {u'$and': [{u'PPP': u'R'}, {u'DDD': u'T'}]}]}
Thanks for the answer. Its also nice. I will try it now.
And one more thing, I have actually omitted the "value" consideration in my example code. I am thankful to you to point that out. I already have a means to achieve that. Thanks anyway.
Upvotes: 0
Reputation: 101122
Your example code does not run, but given that a dict
{'OR': [{'AND': [{'column': 'XXX', 'operator': '=', 'value': 'M'}, {'column': 'YYY', 'operator': '=', 'value': 'N'}]}, {'column': 'YYY', 'operator': '>=', 'value': '3.0'}]}
should be convertet to
{'$or': [{'$and': [{'XXX': 'M'}, {'YYY': 'N'}]}, {'YYY': {'$gte': 3.0}}]}
use something like this:
FILTMAP = {'>=': '$gte', '<=': '$lte', '>': '$gt', '<': '$lt', "!=":"$ne"}
CONJUNCTION_MAP = {"AND":"$and", "OR":"$or"}
def convert_column(dic):
if not dic['operator'] in FILTMAP:
return {dic['column']: dic['value']}
else:
value = float(dic['value']) if dic['operator'] == "!=" else dic['value']
return {dic['column']: {FILTMAP[dic['operator']]: value}}
def convert(dic):
for k,v in dic.items():
if isinstance(v, list):
if k in CONJUNCTION_MAP:
k = CONJUNCTION_MAP[k]
return {k: [convert(i) for i in v]}
else:
return convert_column(dic)
I don't know if it's important to convert '3.0'
to 3.0
. The line
value = float(dic['value']) if dic['operator'] == "!=" else dic['value']
is quite hackish, you want replace it with some appropriate logic to handle those cases.
Upvotes: 3