I have 3 models Company, User, Loan in my Rails application
company.rb
class Company < ApplicationRecord
has_many :users
end
Company id: 1, name: "A", created_at: "2018-02-06 07:34:17", updated_at: "2018-02-06 07:34:17"
Company id: 2, name: "B", created_at: "2018-02-06 07:34:19", updated_at: "2018-02-06 07:34:19"
Company id: 3, name: "C", created_at: "2018-02-06 07:34:21", updated_at: "2018-02-06 07:34:21"
user.rb
class User < ApplicationRecord
belongs_to :company
has_many :loans
end
User id: 1, name: "Sachin", company_id: 1, created_at: "2018-02-06 07:35:53", updated_at: "2018-02-06 08:02:41", user_status: true
User id: 2, name: "Ghanshyam", company_id: 1, created_at: "2018-02-06 07:36:01", updated_at: "2018-02-06 08:02:41", user_status: false
User id: 3, name: "Anand", company_id: 1, created_at: "2018-02-06 07:36:06", updated_at: "2018-02-06 08:02:41", user_status: false
User id: 4, name: "Ghanshyam Rahul", company_id: 1, created_at: "2018-02-06 07:36:15", updated_at: "2018-02-06 08:02:41", user_status: false
User id: 5, name: "Anand", company_id: 3, created_at: "2018-02-06 07:43:56", updated_at: "2018-02-06 08:02:41", user_status: false
User id: 6, name: "Ghanshyam", company_id: 3, created_at: "2018-02-06 07:43:58", updated_at: "2018-02-06 08:02:41", user_status: false
loan.rb
class Loan < ApplicationRecord
belongs_to :user
end
Loan id: 1, name: "loan 1", user_id: 1, created_at: "2018-02-06 07:44:46", updated_at: "2018-02-06 07:44:46"
Loan id: 5, name: "loan 5", user_id: 1, created_at: "2018-02-06 07:44:54", updated_at: "2018-02-06 07:44:54"
Loan id: 6, name: "loan 6", user_id: 6, created_at: "2018-02-06 07:45:33", updated_at: "2018-02-06 07:45:33"
Loan id: 7, name: "loan 7", user_id: 6, created_at: "2018-02-06 07:45:34", updated_at: "2018-02-06 07:45:34"
Loan id: 8, name: "loan 8", user_id: 6, created_at: "2018-02-06 07:45:36", updated_at: "2018-02-06 07:45:36"
I want to write down join query(single query) that fetch list of company if there users have any loan like follows :
Company id: 1, name: "A", created_at: "2018-02-06 07:34:17", updated_at: "2018-02-06 07:34:17"
Company id: 3, name: "C", created_at: "2018-02-06 07:34:21", updated_at: "2018-02-06 07:34:21"
Company.joins(users: [:loans]).group('companies.id')
To avoid possible company duplications I would group companies table by company id field.
Company.joins(users: :loans).distinct
Will give you all companies that have users with loan
You create join query that will join company with their users, and give you companies with users, and then join users with their loans. As it is using inner join, when users do not have company they do not appear and their companies do not appear either
Related
I have a simple relation company has many projects and everything is super fine, when I get the result parent ID is missing from entity object while its present in query
Company Entity :
#Entity()
export class Company {
#PrimaryGeneratedColumn({ unsigned: true })
id: number;
#Column({ nullable: false })
name: string;
#Column({
type: 'datetime',
nullable: false,
default: () => 'CURRENT_TIMESTAMP',
})
created_at;
#Column({ nullable: true, type: 'datetime' })
updated_at;
#OneToMany(
type => Project,
project => project.company
)
project: Project[];
}
Project Entity :
#Entity()
export class Project {
#PrimaryGeneratedColumn({ unsigned: true })
id: number;
#Column({ nullable: false })
name: string;
#ManyToOne(
type => Company,
company => company.project,
{ nullable: false }
)
#JoinColumn({ name: 'company_id' })
company: Company;
#Column({
type: 'datetime',
nullable: false,
default: () => 'CURRENT_TIMESTAMP',
})
created_at;
#Column({ nullable: true, type: 'datetime' })
updated_at;
}
Query in service :
return this.companyRepository.find({ where: { id: 1 }, relations: ['project'] })
Query log is :
SELECT
`Company`.`id` AS `Company_id`,
`Company`.`name` AS `Company_name`,
`Company`.`created_at` AS `Company_created_at`,
`Company`.`updated_at` AS `Company_updated_at`,
`Company__project`.`id` AS `Company__project_id`,
`Company__project`.`name` AS `Company__project_name`,
`Company__project`.`created_at` AS `Company__project_created_at`,
`Company__project`.`updated_at` AS `Company__project_updated_at`,
`Company__project`.`company_id` AS `Company__project_company_id`
FROM
`company` `Company`
LEFT JOIN
`project` `Company__project` ON `Company__project`.`company_id` = `Company`.`id`
WHERE
`Company`.`id` = 1;
but when i print result my company object contains project array but in project array company_id is missing or typeorm has excluded it while creating an object, is there any way than i can get parent_id which is company_id in project object
Result :
Company {
id: 1,
name: 'company',
created_at: 2020-10-24T18:46:59.000Z,
updated_at: null,
project: [
Project {
id: 1,
name: 'project 1',
created_at: 2020-10-24T18:47:35.000Z,
updated_at: null
},
Project {
id: 2,
name: 'project 2',
created_at: 2020-10-24T19:08:08.000Z,
updated_at: null
}
]
}
expected result :
Company {
id: 1,
name: 'company',
created_at: 2020-10-24T18:46:59.000Z,
updated_at: null,
project: [
Project {
id: 1,
company_id: 1, <========= this is required
name: 'project 1',
created_at: 2020-10-24T18:47:35.000Z,
updated_at: null
},
Project {
id: 2,
company_id: 1,
name: 'project 1',
created_at: 2020-10-24T19:08:08.000Z,
updated_at: null
}
]
}
In the fireld 'company_id' you are not supposed to get the id field of company, as it is the company object itself. So from that object you may get its id. I think that if you would set 'eager: true' on the field, you will get the object in the query, because the default is eager: false.
If what you want is only the id and not the whole object, maube think of a field which is a foreign key to the company id using one-to-one relation, which will give you your wanted reault output
I think you should be able to split that up like this. companyId will automatically be extracted from company.
// ...
#ManyToOne(type => Company, company => company.project)
company: Company;
#Column({nullable: true})
companyId: number;
// ...
Suppose I have a table like this:
and an array of objects which contains [
{ID: '0', Name: 'Leo', Age: 21, CurrentState: 5},
{ID: '1', Name: 'George', Age: 26, , CurrentState: 6},
{ID: '2', Name: 'Diana', Age: 27, , CurrentState: 4}
].
How can I update the columns ID, Name, Age, and CurrentState without affecting the values of IsAdmin column?
If I run the following code
Table.bulkCreate([
{ID: '0', Name: 'Leo', Age: 21, CurrentState: 5},
{ID: '1', Name: 'George', Age: 26, , CurrentState: 6},
{ID: '2', Name: 'Diana', Age: 27, , CurrentState: 4}
], {
updateOnDuplicate: true
})
All the values of IsAdmin of the updated rows will be set to FALSE, which is its default value.
How can I avoid this problem?
Just passe an array of only the attributes that need to be updated
Table.bulkCreate([
{ID: '0', Name: 'Leo', Age: 21, CurrentState: 5},
{ID: '1', Name: 'George', Age: 26, , CurrentState: 6},
{ID: '2', Name: 'Diana', Age: 27, , CurrentState: 4}
], {
updateOnDuplicate: ['Name','CurrentState']
})
options.updateOnDuplicate
Array
optional
Fields to update if row key already exists (on duplicate key update)? (only supported by mysql). By default, all fields are updated.
I have 3 models:
class SocialAccount < ActiveRecord::Base
has_many :message_social_accounts
has_many :messages, through: :message_social_accounts
end
class MessageSocialAccount < ActiveRecord::Base
belongs_to :message
belongs_to :social_account
end
class Message < ActiveRecord::Base
has_many :message_social_accounts
has_many :social_accounts, through: :message_social_accounts
end
Having a number of specific social accounts I am trying to establish which ones of these did not receive a message yet.
I am trying to create a join query to find social accounts from the database:
a) that have ids in [1..20] and
b) that have dont have any message_social_account records with message id = 1
Tried this join:
SocialAccount.select('social_accounts.*').joins(:message_social_accounts).group('social_accounts.id').where("social_accounts.id IN (#{potential_recipients.map{|x|x.id}.join(',')}) AND message_social_accounts.message_id IS NOT #{self.id}").to_a
but it hasn't returned the desired result. Can clues? Thanks
EDIT
The following query was created as a result:
"SELECT social_accounts.* FROM \"social_accounts\" INNER JOIN \"message_social_accounts\" ON \"message_social_accounts\".\"social_account_id\" = \"social_accounts\".\"id\" WHERE (social_accounts.id IN (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20) AND message_social_accounts.message_id IS NOT 1) GROUP BY social_accounts.id"
EDIT2
example of message_social_account records
#<MessageSocialAccount id: 4, message_id: 4, social_account_id: 4, read_time: "2000-01-01 12:06:40", created_at: "2015-02-20 20:43:46", updated_at: "2015-02-20 20:43:46", push_notification: nil>,
#<MessageSocialAccount id: 5, message_id: 5, social_account_id: 3, read_time: "2000-01-01 11:34:34", created_at: "2015-02-20 20:43:46", updated_at: "2015-02-20 20:43:46", push_notification: nil>,
#<MessageSocialAccount id: 6, message_id: 6, social_account_id: 2, read_time: "2000-01-01 02:13:25", created_at: "2015-02-20 20:43:46", updated_at: "2015-02-20 20:43:46", push_notification: nil>,
#<MessageSocialAccount id: 33, message_id: 33, social_account_id: 3, read_time: "2000-01-01 13:40:21", created_at: "2015-02-20 20:43:46", updated_at: "2015-02-20 20:43:46", push_notification: nil>,
#<MessageSocialAccount id: 36, message_id: 36, social_account_id: 4, read_time: nil, created_at: "2015-02-20 20:43:46", updated_at: "2015-02-20 20:43:46", push_notification: nil>,
#<MessageSocialAccount id: 37, message_id: 37, social_account_id: 2, read_time: nil, created_at: "2015-02-20 20:43:46", updated_at: "2015-02-20 20:43:46", push_notification: nil>,
#<MessageSocialAccount id: 42, message_id: 42, social_account_id: 3, read_time: "2000-01-01 09:32:45", created_at: "2015-02-20 20:43:46", updated_at: "2015-02-20 20:43:46", push_notification: nil>,
#<MessageSocialAccount id: 44, message_id: 45, social_account_id: 1, read_time: nil, created_at: "2015-03-02 16:07:31", updated_at: "2015-03-02 16:07:40", push_notification: true>,
#<MessageSocialAccount id: 45, message_id: 45, social_account_id: 2, read_time: nil, created_at: "2015-03-02 16:07:31", updated_at: "2015-03-02 16:07:31", push_notification: nil>,
#<MessageSocialAccount id: 46, message_id: 45, social_account_id: 3, read_time: nil, created_at: "2015-03-02 16:07:31", updated_at: "2015-03-02 16:07:31", push_notification: nil>
In MySQL Rails 3 application, one of my columns are serialized to Hash. My question is simple: how can I get results based on this column?
I tried this approach:
example_hash = {id: 666}
ExampleTable.last.hash == example_hash
:true ###### Here you can see that both hashes are the same
Still, a query like this give me no results and no exceptions:
ExampleTable.where('hash LIKE ?', example_hash)
It just doesn't detect the record I need.
my_hash = {id:666}
search_term = my_hash.serializable_hash
ExampleTable.where(search_term)
I tried this in an existing Rails 4 app. You will have to test if it works in Rails 3. I don't have include ActiveModel::Serialization in my model and it still works.
Here is my console session:
Loading development environment (Rails 4.0.0)
$pry(main)> t = Tool.first
Tool Load (10.9ms) SELECT "tools".* FROM "tools" ORDER BY "tools"."id" ASC LIMIT 1
=> #<Tool id: 2, name: "6", serial: "134989652", purchased: nil, put_in_service: nil, cost: nil, value: nil, in_service: true, retired: nil, created_at: "2013-07-17 06:12:59", updated_at: "2014-02-13 17:19:10", note: "", condition: "5 - Brand New Condition", old_location: "Sta 75", model: "Stihl 066", loaner: false, location_id: 9, category_id: 2, annual_service: false>
$pry(main)> x = t.serializable_hash
=> {"id"=>2,
"name"=>"6",
"serial"=>"134989652",
"purchased"=>nil,
"put_in_service"=>nil,
"cost"=>nil,
"value"=>nil,
"in_service"=>true,
"retired"=>nil,
"created_at"=>Tue, 16 Jul 2013 23:12:59 PDT -07:00,
"updated_at"=>Thu, 13 Feb 2014 09:19:10 PST -08:00,
"note"=>"",
"condition"=>"5 - Brand New Condition",
"old_location"=>"Sta 75",
"model"=>"Stihl 066",
"loaner"=>false,
"location_id"=>9,
"category_id"=>2,
"annual_service"=>false}
$pry(main)> Tool.where(x)
Tool Load (10.3ms) SELECT "tools".* FROM "tools" WHERE "tools"."id" = 2 AND "tools"."name" = '6' AND "tools"."serial" = '134989652' AND "tools"."purchased" IS NULL AND "tools"."put_in_service" IS NULL AND "tools"."cost" IS NULL AND "tools"."value" IS NULL AND "tools"."in_service" = 't' AND "tools"."retired" IS NULL AND "tools"."created_at" = '2013-07-17 06:12:59.638381' AND "tools"."updated_at" = '2014-02-13 17:19:10.674233' AND "tools"."note" = '' AND "tools"."condition" = '5 - Brand New Condition' AND "tools"."old_location" = 'Sta 75' AND "tools"."model" = 'Stihl 066' AND "tools"."loaner" = 'f' AND "tools"."location_id" = 9 AND "tools"."category_id" = 2 AND "tools"."annual_service" = 'f'
=> [#<Tool id: 2, name: "6", serial: "134989652", purchased: nil, put_in_service: nil, cost: nil, value: nil, in_service: true, retired: nil, created_at: "2013-07-17 06:12:59", updated_at: "2014-02-13 17:19:10", note: "", condition: "5 - Brand New Condition", old_location: "Sta 75", model: "Stihl 066", loaner: false, location_id: 9, category_id: 2, annual_service: false>]
I'm having trouble wrapping my head around more advanced Rails query methods. In this case, I have three tables: Users, Friendships, and Events.
I have set it up as follows in the models for each
User-> :has_many => :friendships, :has_many => :items
Friendship-> :belongs_to => :user
Event-> belongs_to => :user
Friendships are simply two columns: "user_id" and "friend_id" so each new friendship would create two new rows.
Here is the query I'm using to find "the first four events belonging to a friend of the current_user that has a start_date that is later than right now."
find_by_sql(["SELECT DISTINCT e.id
FROM events e
WHERE e.start_date > ?
AND e.user_id IN(
SELECT f.user_id
FROM friendships f
WHERE f.friend_id = ?)
LIMIT 0,4", Time.zone.now,current_user.id])
What is the true and elegant way to do something like this in Rails? I have a feeling this is also extremely inefficient...
You should be able to use :join and :conditions
time_range = (Time.now.midnight - 4.days)..Time.now.midnight
Event.all :joins => :friendships, :conditions =>
{'start_date' => time_range, 'friendships.friend_id' => current_user.id}, :limit => 4
I haven't really done a whole lot of complex querying like this, but I pieced this together from the examples here: http://guides.rubyonrails.org/active_record_querying.html
Edit:
You may have to add to Event:
has_many :friends, :through => :friendships
Edit2: Looks like you'll have to actually use a nested join:
Event.all :joins => {:user => :friendships }, :conditions => {'start_date' => time_range, 'friendships.friend_id' => current_user.id }
Here is the model code that I used:
class User < ActiveRecord::Base
has_many :events, :foreign_key => "user_id"
has_many :friendships
has_many :friends, :through => :friendships, :source => :user, :uniq => true
end
class Event < ActiveRecord::Base
belongs_to :user
has_many :friendships, :through => :user
end
class Friendship < ActiveRecord::Base
belongs_to :user
end
And, some example output if that may be helpful at all:
>> Event.all :joins => {:user => :friendships }, :conditions => {'happens_on' => time_range, 'friendships.user_id' => 1 }
Event.all :joins => {:user => :friendships }, :conditions => {'happens_on' => time_range, 'friendships.user_id' => 1 }
=> [#<Event id: 1, happens_on: "2010-08-06 00:42:37", title: "Jims party", description: "Happy Birthday", created_at: "2010-08-03 00:42:37", updated_at: "2010-08-03 00:42:37", user_id: 1>]
>> jim = User.find(1)
jim = User.find(1)
=> #<User id: 1, name: "Jim", bio: "Loves Rails", age: 30, created_at: "2010-08-03 00:30:51", updated_at: "2010-08-03 00:30:51">
>> crystal = User.find(2)
crystal = User.find(2)
=> #<User id: 2, name: "Crystal", bio: "Loves writing", age: 26, created_at: "2010-08-03 00:31:14", updated_at: "2010-08-03 00:31:14">
>> jim.events
jim.events
=> [#<Event id: 1, happens_on: "2010-08-06 00:42:37", title: "Jims party", description: "Happy Birthday", created_at: "2010-08-03 00:42:37", updated_at: "2010-08-03 00:42:37", user_id: 1>]
>> event1 = jim.events[0]
event1 = jim.events[0]
=> #<Event id: 1, happens_on: "2010-08-06 00:42:37", title: "Jims party", description: "Happy Birthday", created_at: "2010-08-03 00:42:37", updated_at: "2010-08-03 00:42:37", user_id: 1>
>> event1.user
event1.user
=> #<User id: 1, name: "Jim", bio: "Loves Rails", age: 30, created_at: "2010-08-03 00:30:51", updated_at: "2010-08-03 00:30:51">
>> event1.friendships
event1.friendships
=> [#<Friendship user_id: 1, friend_id: nil, created_at: "2010-08-03 00:57:31", updated_at: "2010-08-03 00:57:31">]
>>