Python札記 -- MongoDB模糊查詢

    最近在使用MongoDB的時候,遇到了使用多個關鍵詞進行模糊查詢的場景。竹風使用的是mongoengine庫。python

    查了各類資料,最後總結出比較好用的方法。先上代碼,後面進行詳細說明。以下:正則表達式

 1 #!/usr/bin/env python
 2 #coding:utf-8
 3 
 4 import re
 5 import mongoengine
 6 from mongoengine import *
 7 
 8 mongoengine.register_connection('default', 'test', host='127.0.0.1')
 9 
10 class TestData(Document):
11     name = StringField()
12     content = StringField()
13 
14 TestData.objects.get_or_create(name='天地玄黃',defaults={'content':'abc123'})
15 TestData.objects.get_or_create(name='宇宙洪荒',defaults={'content':'ABC123'})
16 TestData.objects.get_or_create(name='每天向上',defaults={'content':'Abc123'})
17 
18 def print_arr(obj):
19     print obj.name,obj.content
20 
21 def fuzzy_query_by_contains():
22     print "\n###使用mongoengine的contains進行查詢"
23     print "#contains區分大小寫:"
24     test_data_list = TestData.objects(content__contains='abc123')
25     map(print_arr,test_data_list)
26 
27     print "#icontains不區分大小寫:"
28     test_data_list = TestData.objects(content__icontains='abc123')
29     map(print_arr,test_data_list)
30 
31 def fuzzy_query_by_Q():
32     print "\n###使用Q來進行查詢"
33     test_data_list = TestData.objects(
34         Q(name__icontains=u'天地') | Q(name__icontains=u'宇宙'))
35     map(print_arr,test_data_list)
36 
37 def fuzzy_query_by_pymongo():
38     print "\n###使用raw queries,New in version 0.4"
39     print "#單個查詢條件"
40     search = {
41         '__raw__':{
42             'content':{'$regex':'A\S+\d+'},
43         },
44     }
45     test_data_list = TestData.objects(**search)
46     map(print_arr,test_data_list)
47 
48     print "#多個查詢條件"
49     search = {
50         '__raw__':{
51             'name':{'$in':[re.compile(u'每天'),re.compile(u'宇宙')]},
52         },
53     }
54     test_data_list = TestData.objects(**search)
55     map(print_arr,test_data_list)
56 
57 if __name__ == '__main__':
58     fuzzy_query_by_contains()
59     fuzzy_query_by_Q()
60     fuzzy_query_by_pymongo()

     先討論一下fuzzy_query_by_contains方法,這裏用的是mongoengine提供的contains操做。值得注意的是,contains區分大小寫,而icontains不區分大小寫。這種方式在針對一個關鍵詞進行模糊查詢的時候特別方便。mongodb

    而後是fuzzy_query_by_Q方法,這裏結合了contains和Q來進行組合查詢。當使用Q()來進行組合查詢時,必須使用位運算符(|和&),而不能使用or,and來進行邏輯運算。這種方式比較合適肯定關鍵詞數目的狀況。若是關鍵詞的數目是不定的,這種方式就略顯糾結了。spa

    竹風在動態關鍵詞模糊查詢的問題也是糾結良久,差點就要對每一個關鍵詞分別查詢,而後取交集湊結果了。後來在文檔中發現,mongoengine有__raw__這個參數,能夠執行PyMongo的查詢(version 0.4提供的新功能)。因而幾經試驗,fuzzy_query_by_pymongo方法就出爐了。
    PyMongo支持正則表達式,提供了兩種方法,一種是使用$regex,另外一種是使用re.compile()。
    在例子中,對單個關鍵詞進行模糊查詢,對應的代碼爲:{'$regex':'A\S+\d+'}
    接着就是對多個關鍵詞進行查詢,對應的代碼爲:{'$in':[re.compile(u'每天'),re.compile(u'宇宙')]}code

    對代碼進行一些修改,以便接受多個關鍵詞,代碼以下:對象

1 def fuzzy_query_by_pymongo():
2     print "#多個查詢條件"
3     keyword = u'每天 宇宙'
4     search = {'__raw__' : {'name':{'$in':map(re.compile,keyword.split())}}}
5     test_data_list = TestData.objects(**search)
6     map(print_arr,test_data_list)

    順帶一提,例子中建立數據是用的get_or_create,會返回一個元組,第一個元素是建立or查詢的對象,第二個元素是是否建立成功。文檔中的推薦用法以下:blog

1 >>> a, created = User.objects.get_or_create(name='User A', defaults={'age': 30})
2 >>> b, created = User.objects.get_or_create(name='User A', defaults={'age': 40})
3 >>> a.name == b.name and a.age == b.age
4 True

    最後是例子運行的結果,返回的結果順序可能略有不一樣,沒必要在乎。utf-8

 1 $ python mongodb_test.py
 2 
 3 ###使用mongoengine的contains進行查詢
 4 #contains區分大小寫:
 5 天地玄黃 abc123
 6 #icontains不區分大小寫:
 7 天地玄黃 abc123
 8 宇宙洪荒 ABC123
 9 每天向上 Abc123
10 
11 ###使用Q來進行查詢
12 天地玄黃 abc123
13 宇宙洪荒 ABC123
14 
15 ###使用raw queries,New in version 0.4
16 #單個查詢條件
17 宇宙洪荒 ABC123
18 每天向上 Abc123
19 #多個查詢條件
20 宇宙洪荒 ABC123
21 每天向上 Abc123
相關文章
相關標籤/搜索