Multiple join query to exclude certain records - mysql

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>

Related

How to fetch objects in joins?

This is my schema :
Mention.rb
belongs_to :user
create_table "mentions", force: :cascade do |t|
t.integer "user_id", limit: 4
t.integer "mentionable_id", limit: 4
t.string "mentionable_type", limit: 191
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "deleted_at"
end
User.rb
No Association.
Query:
mentions = Mention.joins(:user).where(mentions: {mentionable_type: 'Comment', mentionable_id: #comments_ids}).select('users.*, mentions.mentionable_id AS comment_id').group_by(&:comment_id)
Output :
=> {155=>
[#<Mention:0x00007ff51a309de8 id: 110, created_at: Thu, 07 Nov 2019 10:19:46 UTC +00:00, updated_at: Thu, 07 Nov 2019 10:19:46 UTC +00:00, deleted_at: nil>,
#<Mention:0x00007ff51a3092f8 id: 112, created_at: Thu, 07 Nov 2019 10:19:46 UTC +00:00, updated_at: Thu, 07 Nov 2019 10:19:46 UTC +00:00, deleted_at: nil>],
156=>[#<Mention:0x00007ff51a3098e8 id: 111, created_at: Thu, 07 Nov 2019 10:19:46 UTC +00:00, updated_at: Thu, 07 Nov 2019 10:19:46 UTC +00:00, deleted_at: nil>]}
id:110 that is here in the output is of user and 115 is mentionable_id.
How can I get complete user object with group_by mentionable_id ?
Expected:
=> {155=>
[#<User:0x00007ff51a309de8 id: 110, name: "abc", email: 'xyz#mail.com', deleted_at: nil>,
#<User:0x00007ff51a3092f8 id: 112, name: "abc", email: 'xyz#mail.com', deleted_at: nil>],
156=>[#<User:0x00007ff51a3098e8 id: 111, name: "abc", email: 'xyz#mail.com', deleted_at: nil>]}
You need to query through User:
User.joins(:mentions)
.where(mentions: { mentionable_type: 'Comment', mentionable_id: #comments_ids })
.select('users.*, mentions.mentionable_id AS comment_id')
.group_by(&:comment_id)

Nested Joins in Rails

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

Is it possible to partially update rows using sequelize?

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.

HighCharts - Filling a heatmap from SQL Query

Im trying to fill a HighCharts Heatmap with data returned from an SQL Query.
What i have in the JS file is
$(function () {
var chart;
$(document).ready(function() {
$.getJSON("php/all-counties-sales-data-box.php", function(json) {
chart = new Highcharts.Chart({
chart: {
renderTo: 'chart-box-combined',
type: 'heatmap',
marginTop: 40,
marginBottom: 80,
plotBorderWidth: 1
},
title: {
text: 'Sales per employee per weekday'
},
xAxis: {
categories: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
},
yAxis: {
categories: ['Lucozade', 'Rockstar', 'Sprite', 'Monster', '7Up', 'Fanta', 'Coke'],
title: null
},
colorAxis: {
min: 0,
minColor: '#FFFFFF',
maxColor: Highcharts.getOptions().colors[0]
},
legend: {
align: 'right',
layout: 'vertical',
margin: 0,
verticalAlign: 'top',
y: 25,
symbolHeight: 280
},
tooltip: {
formatter: function () {
return '<b>' + this.series.xAxis.categories[this.point.x] + '</b> sold <br><b>' +
this.point.value + '</b> items on <br><b>' + this.series.yAxis.categories[this.point.y] + '</b>';
}
},
series: [{
name: 'Sales per Shell',
borderWidth: 1,
data:
[[0, 0, 10], [0, 1, 19], [0, 2, 8], [0, 3, 24], [0, 4, 67], [0, 5, 67], [0, 6, 67],
[1, 0, 92], [1, 1, 58], [1, 2, 78], [1, 3, 117], [1, 4, 48], [1, 5, 48], [1, 6, 48],
[2, 0, 35], [2, 1, 15], [2, 2, 123], [2, 3, 64], [2, 4, 52],
[3, 0, 72], [3, 1, 132], [3, 2, 114], [3, 3, 19], [3, 4, 16],
[4, 0, 38], [4, 1, 5], [4, 2, 8], [4, 3, 117], [4, 4, 115],
[5, 0, 88], [5, 1, 32], [5, 2, 12], [5, 3, 6], [5, 4, 120],
[6, 0, 13], [6, 1, 44], [6, 2, 88], [6, 3, 98], [6, 4, 96],
[7, 0, 31], [7, 1, 1], [7, 2, 82], [7, 3, 32], [7, 4, 30],
[8, 0, 85], [8, 1, 97], [8, 2, 123], [8, 3, 64], [8, 4, 84],
[9, 0, 47], [9, 1, 114], [9, 2, 31], [9, 3, 48], [9, 4, 91],
[10, 0, 47],
[11, 0, 47],
],
dataLabels: {
enabled: true,
color: '#000000'
}
}]
});
});
});
});
And what im trying to fill it with is data from the query
$sth = mysql_query("Select SUM(Profit) as profitSum From FactSales GROUP BY ShellType, SaleMonth");
$rows1 = array();
$rows1['profit'] = 'profitSum';
while($rr = mysql_fetch_assoc($sth)) {
$rows1['series'][] = $rr['profitSum'];
}
$result = array();
array_push($result,$rows1);
What do i actually need to change for the "series" data to be filled with the data returned from the sql query?
Heres the JSON response as requested
[{"profit":"profitSum","data":[1329230,1796743,1789417,1327813,1457103,1198845,1859826,1770589,1555410,1310369,2183499,1212897,6424306,6426002,6345153,6167415,6969392,5974880,6407699,6278843,6622002,5962102,5198177,5386392,72991,2321397,1751565,2029890,642041,1314314,1322492,1557859,1647784,1831767,1347480,1739353,1742597,1636006,1728247,1709689,1206645,1383206,1119153,1378317,1527356,1937898,1485322,1404498,1868629,1635265,1860456,1293870,1485349,2031389,1834402,1291372,1838382,1616009,781641,1421830,1763592,1279535,1123468,2024766,975863,1461843,1318585,1137336,1111721,1407705,2349652,1260858,1144070,1219659,1378615,1354139,2015115,1408858,2650864,1810850,1380157,1844909,2055306,1913532,1701963]}]

Elegant Advanced Rails Queries

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">]
>>