2016-02-28 5 views
11

मैं दो मॉडल, गीत और वोट मिल गया है, जहां गीत कई वोटों है। मैं सभी गानों का चयन करना चाहता हूं और प्रत्येक के लिए वोटों की संख्या गिनना चाहता हूं।फीनिक्स में structs में Ecto चुनिंदा प्रश्नों को कैसे चालू करें?

SongController में सूचकांक कार्रवाई, मिश्रण जनरल कार्य उपयोग करते हुए उत्पन्न, यह करने के लिए संशोधित किया गया है:

def index(conn, _params) do 
    query = from s in Song, select: %{id: s.id, name: s.name, artist: s.artist} 
    songs = Repo.all(query) 
    render(conn, "index.html", songs: songs) 
end 

इस मामले songs में सूचियों की एक सूची है। लेकिन मूल, उत्पन्न समारोह में, songs = Repo.all(Song) यह गाने के structs की एक सूची है।

इसका मतलब है कि निम्न त्रुटि संदेश के साथ टेम्पलेट को तोड़ने में song_path कार्य: maps cannot be converted to_param. A struct was expected, got: %{artist: "Stephen", id: 3, name: "Crossfire"}

बेशक

, क्या मैं वास्तव में क्या करना चाहते हैं किसी भी तरह का चयन बयान करने के लिए एक num_votes क्षेत्र को जोड़ने के लिए है, और फिर किसी भी तरह से गाने संरचना के लिए एक समान क्षेत्र बनाते हैं? नोट करने के लिए

+0

मुझे लगता है कि Hex.pm पूरी तरह से अलग सूचियों के द्वारा एक समान समस्या (पैकेज के डाउनलोड की संख्या) हल करता है। ([नियंत्रक] (https://github.com/hexpm/hex_web/blob/master/web/controllers/package_controller.ex#L24), [देखें] (https://github.com/hexpm/hex_web/blob/ मास्टर/वेब/टेम्पलेट्स/पैकेज/index.html।eex # L67)) – Torstein

उत्तर

15

पहले हम गीत स्कीमा के लिए एक virtual field जोड़ना चाहिए ताकि यह num_votes परिणाम स्टोर करने के लिए इस्तेमाल किया जा सकता: हम नक्शे के लिए मायने रखता है जोड़ सकते हैं

defmodule Song do 
    use Ecto.Schema 

    schema "songs" do 
    field :num_votes, :integer, virtual: true 
    ... 
    end 
end 

Ecto.Query.select/3, Ecto.Query.join/5 और Ecto.Query.API.count/1 का एक संयोजन का उपयोग करना

query = from s in Song, 
    left_join: v in assoc(:votes), 
    select: %{id: s.id, name: s.name, artist: s.artist, num_votes: count(v.id)} 

हम तो Kernel.struct उपयोग कर सकते हैं एक struct करने के लिए प्रत्येक आइटम परिवर्तित करने के लिए: आप क्वेरी से चयन करने के लिए प्रयोग कर रहे हैं

+०१२३५१६४१०६१
songs = 
    query 
    |> Repo.all() 
    |> Enum.map(fn(song) -> struct(Song, song) end) 

यह गीत structs की एक सूची देता है जिसका उपयोग दृश्य में किया जा सकता है।

+2

क्वेरी के चुनिंदा भाग में सभी फ़ील्ड को गिनने का कोई तरीका नहीं है, लेकिन "हे, स्कीमा से सभी फ़ील्ड्स का चयन करें और यह num_votes: गिनती() कॉलम"? एक वर्चुअल फ़ील्ड के लिए – vsushkov

+2

मुझे समाधान मिला है: 'चुनें:% {s | num_votes: गिनती (v.id)} ', लेकिन मैं एक और जोड़ने पर अटक गया है। – luzny

1

एक दिलचस्प बात यह है कि structs वास्तव में सिर्फ मॉड्यूल का नाम वे का एक हिस्सा हैं करने के लिए एक __struct__ कुंजी सेट के साथ dicts है। इस वजह से आप बस __struct__ कुंजी को हटाकर एक Dict में एक सामान्य Struct बदल सकते हैं।

iex(1)> defmodule M do 
...(1)> defstruct [:a, :b] 
...(1)> end 

iex(2)> Map.delete(%M{}, :__struct__) 
%{a: nil, b: nil} 

(संदर्भ: https://groups.google.com/forum/#!topic/elixir-lang-talk/2xQqFOZSvk0)

लेकिन अगर आप दूसरी दिशा में जाने के लिए चाहते हैं तो यह सिर्फ एक ही तरीके से Map.add का उपयोग करने में इसे जोड़ने के लिए आसान है। कृपया इस सभी कुंजियों काम करने के लिए, वहाँ हो भले ही आप सिर्फ उन्हें nil को स्थापित कर रहे हैं चाहिए प्राप्त करने के लिए ध्यान दें।

आप के अन्य भाग के लिए

तो सवाल कर रहे हैं। गणना करने के लिए शायद कुछ फैंसी एसक्यूएल तरीका है। मैं आपको ऐसा करने की सलाह दूंगा। मैं एक के लिए शायद इसे एक जुड़ने का उपयोग करके elixir में एक साथ हैक कर सकता हूं और फिर Enum.map उस पर आईएनजी और सूची को एक सूची के बजाय एक पूर्णांक के साथ बदल देता है। जुड़ने के तरीके के बारे में यहां एक लेख दिया गया है: http://blog.plataformatec.com.br/2015/08/working-with-ecto-associations-and-embeds/

मैं ऐसा करने के लिए कैसे करने के लिए के रूप में आप के लिए छोड़।

संबंधित मुद्दे