2015-09-27 11 views
9

Questa è una domanda teorica ma si presuppone che la struttura dei dati non possa cambiare e che questo sia sicuramente il modo in cui si desidera eseguire la query. Questa domanda è più per comprendere meglio lo in modo che i filtri where siano composti dinamicamente da piuttosto che in realtà voler ottenere i risultati da una query come questa.Composizione di una query Ecto con una quantità dinamica di filtri dove

immaginare un database con una tabella di auto in cui ogni macchina ha una colonna manufacturer_id che contiene un ID come "BD324" o "GM512", con "BD" & "GM", considerato come prefissi.

Abbiamo bisogno di fare una ricerca sul tavolo dell'auto in modo che le macchine vengano restituite quando il prefisso manufacturer_id corrisponde a un determinato set di prefissi. Quindi, data una lista di prefissi:

prefixes = ["BD", "GM", "EX", "RD", "DE"] 

..we'd vogliono tornare tutte le automobili che hanno una manufacturer_id che inizia con qualsiasi di quelli elencati. Ad esempio (LIKE x O LIKE y O LIKE z).

il seguente codice Elixir/Ecto sarebbe cercare un prefisso:

search_prefix = Enum.at(prefixes, 0) <> "%" 
from c in Car, where: like(c.manufacturer_id, ^search_prefix) 

come potremmo fare per costruire la clausola where in base alla lista prefixes?

risposta

4

Ecto sembra mancare un modo semplice per unire parti dinamiche di una query con OR, ma potrei aver perso qualcosa. Perfavore, correggimi se sbaglio.

Tuttavia, è possibile utilizzare un equivalente ANY query, che rivendico è sia più facile da leggere e più semplice da costruire:

SELECT * from cars 
WHERE manufacturer_id LIKE ANY(ARRAY['BD%', 'GM%', 'EX%', 'RD%', 'DE%']); 

Per creare questo tipo di domanda con Ecto, è possibile utilizzare un fragment:

prefixes_like = prefixes |> Enum.map(&"#{&1}%") 
from c in Car, 
    where: fragment("? LIKE ANY(?)", c.manufacturer_id, ^prefixes_like), 
    select: c 
+0

Grazie! Ho parlato con José su IRC e questa è davvero la strada da percorrere (almeno per ora). Se il requisito che hai è AND, piuttosto che OR, puoi usare un riduci: 'Enum.reduce prefissi, query, prefisso fn, acc -> da q in acc, dove: like (q.manufacturer_id,^(prefisso < > "%")) end' –

+1

o_query sono state aggiunte in Ecto 2.1 https://github.com/elixir-ecto/ecto/commit/640e8f5f7f97eab68e4eebcd517803f71d90ebc1#commitcomment-18945603 –

3

Si può pensare di comporre query come trasformazione dei dati:

prefixes -> query with multiple where conditions 

Per fare ciò è necessario ridurre una struttura dati a un'altra ed Ecto 2 fornisce or_where che si adatta alle proprie necessità.

Di seguito è riportato un esempio:

def filter_by_prefixes(query, prefixes) do 
    Enum.reduce prefixes, query, fn prefix, query -> 
    filter_by_prefix(query, prefix) 
    end 
end 

def filter_by_prefix(query, prefix) do 
    or_where(query, [c], like(c.manufacturer_id, ^"#{prefix}%")) 
end 

# Then build the query 
Car |> filter_by_prefixes(prefixes) 
+0

Grazie per l'aggiornamento! Questo è stato scritto prima di Ecto 2 ma questa è certamente la strada da percorrere adesso. –

Problemi correlati