Where condition along with group_by oprion in rails - ruby-on-rails-3

I am new to rails so please anybody tell me how to use group_by option in controller page and and along with group_by i want to count the name through the Where Condition

In City Model add a scope.
scope :by_name, lambda { |name| where(name: name) }
When you call count on the scope
City.by_name('London').count
The following MySql will be executed...
SELECT count(*) FROMcitiesWHEREcities.name= 'London'

City.group_by(&:name)
The above statement will give you array of hash, in which key will be city_name and values will be array of city records.
Then if you need only count of each of array of city records for all the cities then you can do it by creating a new variable and storing the count of records along with their name using :
city_count = {}
City.group_by(&:name).each do |city_name, city_records|
city_count[city_name] = city_records.count
end
The above code will return you the array of hash which has key as city_name and the number of records as value.

Related

Cypher - Add multiple connections

I have 2 nodes:
Students and Subjects.
I want to be able to add multiple student names to multiple subjects at the same time using cypher query.
So far I have done it by iterating through the list of names of students and subjects and executing the query for each. but is there a way to do the same in the query itself?
This is the query I use for adding 1 student to 1 subject:
MATCH
(s:Student)-[:STUDENT_BELONGS_TO]->(c:Classroom),
(u:Subjects)-[:SUBJECTS_TAUGHT_IN]->(c:Classroom)
WHERE
s.id = ${"$"}studentId
AND c.id = ${"$"}classroomId
AND u.name = ${"$"}subjectNames
AND NOT (s)-[:IN_SUBJECT]->(u)
CREATE (s)-[:IN_SUBJECT]->(u)
So I want to be able to receive multiple subjectNames and studentIds at once to create these connections. Any guidance for multi relationships in cypher ?
I think what you are looking for is UNWIND. If you have an array as parameter to your query:
studentList :
[
studentId: "sid1", classroomId: "cid1", subjectNames: ['s1','s2'] },
studentId: "sid2", classroomId: "cid2", subjectNames: ['s1','s3'] },
...
]
You can UNWIND that parameter in the beginning of your query:
UNWIND $studentList as student
MATCH
(s:Student)-[:STUDENT_BELONGS_TO]->(c:Classroom),
(u:Subjects)-[:SUBJECTS_TAUGHT_IN]->(c:Classroom)
WHERE
s.id = student.studentId
AND c.id = student.classroomId
AND u.name = in student.subjectNames
AND NOT (s)-[:IN_SUBJECT]->(u)
CREATE (s)-[:IN_SUBJECT]->(u)
You probably need to use UNWIND.
I haven't tested the code, but something like this might work:
MATCH
(s:Student)-[:STUDENT_BELONGS_TO]->(c:Classroom),
(u:Subjects)-[:SUBJECTS_TAUGHT_IN]->(c:Classroom)
WITH
s AS student, COLLECT(u) AS subjects
UNWIND subjects AS subject
CREATE (student)-[:IN_SUBJECT]->(subject)

Rails, joining two tables with where clauses on each tabe

I'm new to web development and rails, and I'm trying to construct a query object for my first time. I have a table Players, and a table DefensiveStats, which has a foriegn-key player_id, so each row in this table belongs to a player. Players have a field api_player_number, which is an id used by a 3rd party that I'm referencing. A DefensiveStats object has two fields that are relevant for this query - a season_number integer and a week_number integer. What I'd like to do is build a single query that takes 3 parameters: an api_player_number, season_number, and week_number, and it should return the DefensiveStats object with the corresponding season and week numbers, that belongs to the player with api_player_number = passed in api_player_number.
Here is what I have attempted:
class DefensiveStatsWeekInSeasonQuery
def initialize(season_number, week_number, api_player_number)
#season_number = season_number
#week_number = week_number
#api_player_number = api_player_number
end
# data method always returns an object or list of object, not a relation
def data
defensive_stats = Player.where(api_player_number: #api_player_number)
.joins(:defensive_stats)
.where(season_number:#season_number, week_number: #week_number)
if defensive_stats.nil?
defensive_stats = DefensiveStats.new
end
defensive_stats
end
end
However, this does not work, as it performs the second where clause on the Player class, and not the DefensiveStats class -> specifically, "SQLite3::SQLException: no such column: players.season_number"
How can I construct this query? Thank you!!!
Player.joins(:defensive_stats).where(players: {api_player_number: #api_player_number}, defensive_stats: {season_number: #season_number, week_number: #week_number})
OR
Player.joins(:defensive_stats).where("players.api_player_number = ? and defensive_stats.season_number = ? and defensive_stats.week_number = ?", #api_player_number, #season_number, #week_number)

Is there a way to combine where and where.not into one condition in Rails?

I have an Event model, that has user_id inside it. I want to select all objects of this model, with specified user_id but not including specific events. So I can do it with a query like that:
Event.where(user_id: user.id).where.not(id: id)
But can I combine these 2 where functions into one?
I know that if I need to find, for example, events with specified ids and user_ids, I can do it this way:
Event.where(user_id: user_id).where(id: id)
and I can compact it using one where call instead of two:
Event.where(user_id: user_id, id: id)
but can I do the same thing if I am using where and where.not?
You can gather
Event.where(user_id: 1) + Event.where.not(id: 2)
or deny a parameter
Event.where(user_id: 1).where.not(id: 2)
You can write as per below to add where and where.not :
Event.where(
"user_id = ? AND id != ?",
user.id,
id
)
so if user_id = 1 and id = 2
than this will return records with user_id 1 and without id 2 :)
try this,you can create two scopes and calling then in chain
scope :with_user, ->(user) {user_id: user.id}
scope :excluded_event, ->(event_ids) { where.not(id: event_ids) }
Event.with_user(user).excluded_event(event_ids)

Subqueries for each row

Using these tables:
*student {'s_id','s_name,'...} , class {'c_id','c_name',...} student2class {'s_id','c_id'}, grades {'s_id','c_id','grade'}*
Is it possible to perform a query (nested query?) put class name as subtitle and then all students (of that class) and grades, next class name as subtitle ...
The result I need is:
Maths
John .... C
Anna .... B
[...]
Biology
Anna .... C
Jack .... A
[...]
For each row from class I'll have a subquery fetching all data related with this class
No need of any sub-query. You can get your data this way:
SELECT c_name, s_name_, grade
FROM student, class, grades
WHERE student.s_id = grades.s_id and class.c_id = grades.c_id
ORDER BY c_name
The presentation of results depends on your system/tools, as others already said. This is a link to the solution for Microsoft Access:
http://office.microsoft.com/en-001/access-help/create-a-grouped-or-summary-report-HA001159160.aspx
The solution should be implemented in your client side code and not in the database. From database you should just get a simple table formatted data (subject, student, grade)
Then convert the above recordset to the format you want:
For an example in C# you could convert the recordset into lookup
var Lookup = DataSet.Tables[0].Rows.ToLookup(x => x["subjectColumn"]);
now you can loop through the lookup and format your result
foreach (var grade in Lookup)
{
subject = grade.Key;
...
}

Rails ActiveRecord Join Query With conditions

I have following SQL Query:
SELECT campaigns.* , campaign_countries.points, offers.image
FROM campaigns
JOIN campaign_countries ON campaigns.id = campaign_countries.campaign_id
JOIN countries ON campaign_countries.country_id = countries.id
JOIN offers ON campaigns.offer_id = offers.id
WHERE countries.code = 'US'
This works perfectly well. I want its rails active record version some thing like:
Campaign.includes(campaign_countries: :country).where(countries: {code: "US"})
Above code runs more or less correct query (did not try to include offers table), issue is returned result is collection of Campaign objects so obviously it does not include Points
My tables are:
campaigns --HAS_MANY--< campaign_countries --BELONGS_TO--< countries
campaigns --BELONGS_TO--> offers
Any suggestions to write AR version of this SQL? I don't want to use SQL statement in my code.
I some how got this working without SQL but surely its poor man's solution:
in my controller I have:
campaigns = Campaign.includes(campaign_countries: :country).where(countries: {code: country.to_s})
render :json => campaigns.to_json(:country => country)
in campaign model:
def points_for_country country
CampaignCountry.joins(:campaign, :country).where(countries: {code: country}, campaigns: {id: self.id}).first
end
def as_json options={}
json = {
id: id,
cid: cid,
name: name,
offer: offer,
points_details: options[:country] ? points_for_country(options[:country]) : ""
}
end
and in campaign_countries model:
def as_json options={}
json = {
face_value: face_value,
actual_value: actual_value,
points: points
}
end
Why this is not good solution? because it invokes too many queries:
1. It invokes query when first join is performed to get list of campaigns specific to country
2. For each campaign found in first query it will invoke one more query on campaign_countries table to get Points for that campaign and country.
This is bad, Bad and BAD solution. Any suggestions to improve this?
If You have campaign, You can use campaign.campaign_countries to get associated campaign_countries and just get points from them.
> campaign.campaign_countries.map(&:points)
=> [1,2,3,4,5]
Similarly You will be able to get image from offers relation.
EDIT:
Ok, I guess now I know what's going on. You can use joins with select to get object with attached fields from join tables.
cs = Campaign.joins(campaign_countries: :country).joins(:offers).select('campaigns.*, campaign_countries.points, offers.image').where(countries: {code: "US"})
You can than reference additional fields by their name on Campaign object
cs.first.points
cs.first.image
But be sure, that additional column names do not overlap with some primary table fields or object methods.
EDIT 2:
After some more research I came to conclusion that my first version was actually correct for this case. I will use my own console as example.
> u = User.includes(:orders => :cart).where(:carts => { :id => [5168, 5167] }).first
> u.orders.length # no query is performed
=> 2
> u.orders.count # count query is performed
=> 5
So when You use includes with condition on country, in campaign_countries are stored only campaign_countries that fulfill Your condition.
Try this:
Campaign.joins( [{ :campaign_countries => :countries}, :offers]).where('`countries`.`code` = ?', "US")