2012-10-04 55 views
4

我有一個Python字典這樣Python字典等效pymongo聲明

{'OR': [{'AND': [{'column': 'XXX', 'operator': '=', 'value': u'M'}, {'column': 'XXX', 'operator': '=', 'value': 'N'}]}, {'column': 'YYY', 'operator': '>=', 'value': '3.0'}]} 

現在,我想把它轉換成類似

{'$or': [{'$and': [{'XXX': 'M'}, {'YYY': 'N'}]}, {'YYY': {u'$gte': 3.0}}]} 

這顯然是相當於pymongo聲明,我相信。

到目前爲止,我寫的代碼是這樣的:

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 

它產生的輸出是:

{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}}]} 

這是附近的解決方案,但沒有一個確切。它適用於像字典

{'AND': [{'column': 'XXX', 'operator': '=', 'value': 'M'}, {'column': 'XXX', 'operator': '=', 'value': 'N'}]} 

OR 

{'column': 'YYY', 'operator': '>', 'value': '1000'} 

你能指點我一個方向嗎?

(這個想法是創建一個通用的。所以,我想產生等同於任何有效的Python解釋成pymongo聲明。最小的是最後一個)

回答

3

你的示例代碼不運行,但因爲一個字典

{'OR': [{'AND': [{'column': 'XXX', 'operator': '=', 'value': 'M'}, {'column': 'YYY', 'operator': '=', 'value': 'N'}]}, {'column': 'YYY', 'operator': '>=', 'value': '3.0'}]} 

應convertet到

{'$or': [{'$and': [{'XXX': 'M'}, {'YYY': 'N'}]}, {'YYY': {'$gte': 3.0}}]} 

使用這樣的事情:

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) 

我不知道將'3.0'轉換爲3.0是否重要。該行

value = float(dic['value']) if dic['operator'] == "!=" else dic['value'] 

是相當hackish,你想用一些適當的邏輯來代替它來處理這些情況。

0

感謝您的回答。我也想出了一些東西。這裏是完整的代碼

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 

請讓我知道您的評論

我嘗試了

{'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'}]}]} 

,這裏是輸出

{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'}]}]} 

感謝您的回答。它也很好。我現在會嘗試。

還有一件事,我實際上省略了示例代碼中的「價值」因素。我很感謝你指出這一點。我已經有了一種方法來實現這一點。不管怎麼說,還是要謝謝你。