2017-05-11 47 views
1

我有一個PostgreSQL表,它有一列帶有一組標籤(標籤列中的數組數據類型)的列。使用Peewee(python ORM),我想選擇所有標籤與列表中任何字符串的部分/子字符串匹配的所有行。LIKE對使用Peewee的數組執行SQL查詢

因此,例如,我可以有一個看起來像這樣的列表:

["stan", "tina"] 

,並應在具有任何標籤afghanistanpakistanstanfordargentina的匹配表中的所有行。

的SQL查詢可以是這個樣子:

SELECT * FROM media WHERE tags::text LIKE ANY (ARRAY[‘%stan%‘, ‘%tina%‘]); 

我將如何做到這一點使用Peewee?

tags列是仿照這樣的:

tags = ArrayField(TextField) 

回答

2

假設你的模型看起來像

from peewee import Model, TextField 
from playhouse.postgres_ext import ArrayField 


class Media(Model): 
    tags = ArrayField(TextField) 

創建與陣列場unnested

from peewee import fn 

subquery = (Media.select(Media.id.alias('id'), 
         fn.unnest(Media.tags).alias('unnested_tags')) 
      .alias('subquery')) 

生成的代碼過濾像

子查詢10
tags = ["stan", "tina"] 
tags_filters = [subquery.c.unnested_tags.contains(tag) for tag in tags] 
tags_filter = reduce(operator.or_, tags_filters) 

和最終的查詢將會

query = (Media.select().join(subquery, 
          on=subquery.c.id == Media.id) 
     .filter(tags_filter) 
     # gets rid of duplicates 
     .group_by(Media.id)) 

P. S.:在的Python 3reduce功能可在functools module而在的Python 2它是一個built-in

+0

嗨!當整個標籤匹配時,我只能得到您的示例工作。我猜這可能是因爲'tags'模型是'ArrayField(TextField)',所以'contains()'只會檢查數組是否與標籤完全匹配,而不是子字符串。 (我編輯了這個問題來澄清的情況:列類型是'ArrayField(TextField)'。) –

+0

@AlfredGodoy:編輯,希望它可以幫助 –

+0

不,它仍然只是匹配完整的標籤。在查看Peewee生成的SQL時,'contains_any()'產生'WHERE t1。「標記」&&%s)','&&'意味着兩個數組至少需要一個相同的值。在我的情況下,'tags'列表包含子字符串/部分,而不是完整的標籤。因此,標籤「istanbul」不與標籤列表中的「stan」相匹配,而是... –