im a beginner with DataMapper ORM, so i have question about complex querying.
First, here is simplified data objects:
class User
property :id, Serial
property :login, String
has n, :actions
end
class Item
property :id, Serial
property :title
has n, :actions
has n, :users, :through => :actions
end
class Action
property :user_id, Integer
property :item_id, Integer
belongs_to :item
belongs_to :user
end
This is how data in db looks like:
+ ------- + + ------- + + ------- +
| Users | | Items | | Actions |
+ ------- + + ------- + + ------- +
| 1 | u1 | | 3 | i1 | | 1 | 4 |
| 2 | u2 | | 4 | i2 | | 1 | 3 |
| ....... | | 5 | i3 | | 1 | 4 |
+ ------- + | ....... | | 1 | 5 |
+ ------- + | 1 | 6 |
| 1 | 3 |
| ....... |
+ ------- +
So, for example User 1 has viewed some items N time. And what i cant figure out, how to select items and their action amount relating to user.
For example, the result for user 1 should be like this:
+ -------------------- |
| Items (item_id, num) |
+ -------------------- |
| 3, 2 |
| 4, 2 |
| 5, 1 |
| 6, 1 |
+ -------------------- +
P.S. regular SQL query that matches my needs:
SELECT i.id, i.title, COUNT(*) as 'num'
FROM actions a
JOIN items i on i.id = a.item_id
WHERE a.user_id = {USERID}
GROUP by a.id
ORDER BY num DESC
LIMIT 10;
So, how to do this and is there are any docs about complex datamapper queries?
In case anybody is still wondering:
Action.aggregate(:item_id, :all.count, :user_id => 1, :order => [item_id.asc])
Will return something like
[ [ 3, 2 ],
[ 4, 2 ],
[ 5, 1 ],
[ 6, 1 ]
]
No way to order by all.count here, but it gets you the data you want :)
As far as I know, there isn't a group by operator in datamapper or any of its plugins. If there were, it would go in dm-aggregates along with the aggregation functions(count,min,max,avg). That makes it difficult to replicate what you want in one query without using sql.
You could try something like this:
require 'dm-aggregates'
Item.all.map do |item|
[item.title,item.actions.count(:user_id=>@user_id)]
end
But, you could just as easily take your sql and wrap it in a fn.
class User
def item_views
repository.adapter.query "SELECT i.id, i.title, COUNT(*) as 'num'
FROM actions a
JOIN items i on i.id = a.item_id
WHERE a.user_id = {USERID}
GROUP by a.id
ORDER BY num DESC
LIMIT 10;"
end
end
repository.adapter.query
returns an Array of structs so you could do things like
user.item_views[0].title
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With