I have the following associations:
class Student < ApplicationRecord
has_many :people_schools
has_many :schools, through: :people_schools
end
class PeopleSchool < ApplicationRecord
belongs_to :student
belongs_to :school
end
class School < ApplicationRecord
has_many :people_schools
has_many :students, through: :people_schools
end
I am trying to get a list of students organized by their school. I have tried the following:
Student.joins(:schools).all.group('schools.name')
but I get the following error:
ActiveRecord::StatementInvalid: PG::GroupingError: ERROR: column "students.id" must appear in the GROUP BY clause or be used in an aggregate function
How do I fix this?
When the association fires, it will generate a SQL query like
SELECT students.id, students. ...
FROM students
JOIN schools
ON ...
GROUP BY schools.name
In sql when grouping, a projection (SELECT) can only include columns that are grouped by or aggregations (e.g. MAX, MIN) of columns (regardless of whether they are grouped by). Therefore adding something like the following would turn it into a valid sql:
# column that is grouped by
Student.joins(:schools).group('schools.name').select('schools.name')
# aggregate function
Student.joins(:schools).group('schools.name').select('schools.name, COUNT(students.id)')
But how you want to fix it in your case depends on what you want to get out of the query.
In answer to the comment
Assuming a student is only member of a single school, which requires changing the association to a belongs_to :school (without the join table) or a has_one :school (with join table).
Student.includes(:school).group_by(&:school)
This will issue an SQL statement to get all students and their school (eager loaded for optimization). Only after the models (Student, School) are instantiated ruby objects, is the group_by method evaluated, which will return a Hash where the school is the key referencing an Array of students.
Related
I have these schemas:
schema "players" do
field :email, :string
has_many :profiles, MyApp.Profile
has_many :worlds, through: [:profiles, :world]
end
schema "worlds" do
field :name, :string
has_many :profiles, MyApp.Profile
has_many :players, through: [:profiles, :player]
end
schema "settings" do
field :mode, :string
belongs_to :player, MyApp.Player
belongs_to :world, MyApp.World
end
All players are supposed to have one settings in each world they create by default. But due to logical errors in our code, some players didn't have settings in some world.
Now I'm trying to find those players who don't have existing settings record in some world so I can create default settings for them using a seeder.
I've tried workarounds like this:
query = from profile in Profile
query
|> Repo.all()
|> Enum.each(fn profile ->
case get_settings(profile.player_id, profile.world_id) do
nil ->
create_settings(profile.player_id, profile.world_id)
_ ->
:ok
end
end)
It works but I want to avoid using the case statement. It costs a lot of database work.
Is there any way to fetch those players with no existing settings record in some worlds using a query?
Use Ecto.Query.join/5 and Ecto.Query.subquery/2 more or less like
subquery =
from profile in Profile,
join: player in Player,
on: player.id == profile.player_id,
join: world in World,
on: world.id == profile.world_id
query =
from setting in Settings,
join: profile in subquery(subquery),
on: setting.player_id == profile.player_id and
setting.world_id == profile.world_id
or, even easier, you might directly join settings to profiles on player_id and world_id.
The latter reveals that you actually have a design flaw. Settings and profiles are basically the same entity, represented twice. That’s why you have inconsistency. Enrich profiles with whatever fields in settings and get rid of settings at all.
post.similarities.order("similarity DESC").group_by(:afterscholar_id).first(4).each_with_index
My post has similarities, and I need to be searching exclusively through the ones that contain anything more than 'nil' in the variable afterscholar_id
I have a couple base models, Post and Comment, with a post having many comments:
class Post < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to: :post
end
I also have single table inheritance on each of these models, with the child classes not having their own database tables. I have type columns in the posts and comments tables.
class ChildPost < Post
has_many :child_comments, class_name: "Comment"
end
class ChildComment < Comment
belongs_to :child_post, class_name: "ChildPost"
end
Now if I create some of these objects
child_comment = ChildComment.create
child_post = ChildPost.create
child_post.child_comments << child_comment
child_post.save
When I do child_post.child_comments I get:
PG::UndefinedColumn: ERROR: column comments.child_post_id does not exist
It's correct that the column child_post_id doesn't exist (it's post_id), but what do I need to do to correct this?
In terms of design, I've set things up this way because the data of a child_comment and a comment are the same, but they have slightly different behavior. I want ChildComment to override only some methods of Comment. And I want a comment and child_comment to be distinguishable database entries.
If there's a better design here, I'm open to it.
You need to specify both :class_name and :foreign_key in your has_many association:
has_many :child_comments, class_name: "Comment", :foreign_key => "post_id"
The :foreign_key option lets you set the name of the foreign key directly. So, if you set that to post_id, then it will work because post_id column is present in the comments table.
I'm wondering on how to do a many to many relationship with mongoid. Here is a visual representation of the models, with the small ones being join tables:
!http://i.imgur.com/lJxoRSb.jpg
I have set up my model like this (as an example) using RoR:
class Event
include Mongoid::Document
field :name, type: String
field :place, type: String
field :when, type: String
field :price, type: Integer
field :participants, type: Integer
field :short_description, type: String
has_many :users
#has_many :users, :through => :user_events
end
what would i need to join the event model with user model with interest model (if this is even possible)? I know mongoid isn't the best option for this but i'm stuck with using it.
Thanks in advance!
Try the following:
embeds_many :user_events
See also http://mongoid.org/en/mongoid/v3/relations.html#embeds_many
Do not use join tables in MongoDB, use arrays of embedded objects/references instead. MongoDB has array values, take advantage of them!
With a many-to-many relationship, you have a choice on placing the references on the first collection, or the second collection, or on both. If you put references in both collections, you have to do your own updates for consistency as needed by your application.
How do I create a polymorphic relation using the MySQL Workbench tool? I want to be able to handle something like what Rails gives me with:
class Example < ActiveRecord::Base
belongs_to :someone, polymorphic: true
end
class PolyOne < ActiveRecord::Base
has_many :examples, as: :someone
end
class PolyTwo < ActiveRecord::Base
has_many :examples, as: :someone
end
If you utilize the "Place a relationship using existing columns," the icon with the 1:N and dropper, you'll be able to accomplish this task. In the examples table (Rails always pluralizes), make sure you have two columns: someone_id and someone_type. In the polymorphic tables, you should already have an id column. Then, you choose the tool mentioned at first (1:N with dropper) and click on someone_id followed by the id of the polymorphic table. This will create a new 1:N relationship between those two fields without inserting any new fields into the tables. Repeat this process for each connected polymorphic table. It will then represent the polymorphic relationship that Rails uses. If you are trying to mimic this on your own without Rails, you'll need to be sure to set the someone_id and someone_type appropriately so that you can follow the polymorphic relationship properly.