2016-02-28 84 views
11

我有兩種模式,歌曲和投票,歌曲有很多票。我想選擇所有歌曲並計算每個歌曲的票數。如何將Ecto選擇查詢轉換爲Phoenix中的結構?

在SongController index操作,利用混合根任務生成,已被修改爲這樣:

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)這是一個列表宋結構

這意味着,與以下錯誤消息的模板斷裂song_path功能:maps cannot be converted to_param. A struct was expected, got: %{artist: "Stephen", id: 3, name: "Crossfire"}

當然,我真正想要做的是一個num_votes場莫名其妙添加到SELECT語句,然後以某種方式對宋體結構做出相應的字段?

+0

我看到Hex.pm通過完全分開的列表解決了類似的問題(一個包的下載次數)。 ([Controller](https://github.com/hexpm/hex_web/blob/master/web/controllers/package_controller.ex#L24),[View](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/3Ecto.Query.join/5Ecto.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每個項目轉換成一個結構:

songs = 
    query 
    |> Repo.all() 
    |> Enum.map(fn(song) -> struct(Song, song) end) 

這將返回可在視圖中使用的歌曲結構列表。

+2

有沒有一種方法來枚舉查詢的選擇部分中的所有字段,但說ecto「嘿,從模式加上這個num_votes:count()列」選擇所有字段? – vsushkov

+2

我已經找到了一個虛擬字段解決方案:'select:%{s | num_votes:count(v.id)}',但我堅持添加更多然後一個。 – luzny

1

一個有趣的事情要注意的是,結構實際上只是一個__struct__鍵設置爲它們所屬的模塊名稱的字符。正因爲如此,您可以通過簡單地刪除__struct__鍵來將常規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

因此,對於你的其他部分是問題。有可能是一些奇特的SQL方法來獲得計數。我會建議你這樣做。我爲一個人可能只是使用加入在elixir中一起攻擊它,然後使用整數而不是列表替換計數。以下是關於如何執行連接的文章:http://blog.plataformatec.com.br/2015/08/working-with-ecto-associations-and-embeds/

我會告訴你如何做到這一點。