Count number of times entity is referenced in association table - sqlalchemy

With the following tables:
class Person(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(1000), nullable=False)
class Group(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(1000), nullable=False)
people = db.relationship('Person', secondary=people, lazy='subquery', backref=db.backref('groups', lazy=True))
people = db.Table(
'people',
db.Column('person_id', db.Integer, db.ForeignKey('person.id'), primary_key=True),
db.Column('group_id', db.Integer, db.ForeignKey('group.id'), primary_key=True)
)
I am trying to write a query that will return me the number of times each person appears in a group.
What I need the query to return with example
I have two entries in Person: Bob and Alice
Bob is referenced in 5 groups
Alice is referenced in 4 groups
I would want the query to return something like the following:
_____________________________________________
| Person | Number of groups referenced in |
|__________|_________________________________|
| Bob | 5 |
|__________|_________________________________|
| Alice | 4 |
|__________|_________________________________|
Thanks in advance!
EDIT:
I have tried the following:
result = db.session.query(Person.name, db.func.count(people.c.person_id).label('total')).join(people).all()
But I'm receiving one result of a single name with a count of all records in the table.

Related

Laravel Eloquent and 3 table relationship

I'm looking for some help in working out how to setup the Eloquent relationships for my application.
I have created migrations for three tables.
| users | | items | | user_items |
+-----------+ +-----------+ +------------+
| id | | id | | id |
| username | | name | | user_id |
| item_id |
| qty |
I have setup an unique index on the user_items table, limiting 1 user id to 1 item id, but with a qty column. I want to setup Eloquent so that I have two models, User and Item. Where I could say:
$item = $user->items()->first();
$name = $item->name;
$qty = $item->qty;
The problem is I'm trying to figure out if I need a 3rd model, UserItem or not.
What are you doing here is actually a M:M relationships, and Laravel Eloquent already have support for that out of the box. The user_item table you have is referred to as the pivot table.
Here's how to setup your relationship using Eloquent.
// User class
class User extends Eloquent {
public items() {
return $this->belongsToMany(Item::class)->withPivot('qty');
}
}
class Item extends Eloquent {
public function users() {
return $this->belongsToMany(User::class)->withPivot('qty');
}
}
For this to work, you will need three migrations:
one for the user table
one for the item table
one for the item_user table. In Eloquent, the pivot table consists of the two tables names in alphabetical order. separated with a dash.
following Eloquent conventions, if you set the FK to use _id, Eloquent will not need additional information. So, in your case, the FK in the item_user table should be user_id and item_id respectively.
There is no need for a ItemUser model. You can access the pivot in the relationship by doing:
$user = User::find(1);
$user->items[0]->pivot->qty; // retrieve the quantity

Grails HQL representation of a query

I'm stuck representing in HQL the following MySQL query
SELECT t1.id as user_id, t2.id as follow_id
FROM user t1
INNER JOIN follows t2 ON
(t2.follower_id = <user id> AND t2.followee_id = t1.id) OR
(t2.follower_id = t1.id AND t2.followee_id = <user id>)
WHERE t1.active = true
ORDER BY t1.id
Can you please help me out with the representation?
Thanks!
Edit:
So far I've tried the following HQL query, but it fails to return the proper data:
SELECT t1
FROM User t1
JOIN t1.follows t2
JOIN t2.follower follower
JOIN t2.followee followee
WHERE (follower.id = :usr AND followee.id = t1.id) OR
(follower.id = t1.id AND followee.id = :usr)
AND t1.active = true
ORDER BY t1.id
The idea is that I have two tables:
User table:
+------+--------+-------------+
| id | name | last_name |
+------+--------+-------------+
| 1 | Jhon | Doe |
| 2 | Jane | Doe |
| 3 | Alfred | Hitchcock |
+------+--------+-------------+
Follows table:
+------+-------------+-------------+
| id | follower_id | followee_id |
+------+-------------+-------------+
| 1 | 1 | 3 |
| 2 | 3 | 2 |
| 3 | 2 | 1 |
+------+-------------+-------------+
What I need is, for example, obtain the name and last name of all users who follow or are being followed by, let's say, user id 1.
The SQL query I posted does exactly this, but I cannot seem to replicate the same behaviour in HQL.
2nd Edit:
My simplified domain classes are:
class User {
String name
String lastName
...
static hasMany = [ follows: Follows ]
static mappedBy = [ follows: 'follower' ]
}
And...
class Follows {
User Followee
...
static belongsTo = [follower: User]
}
The important thing to keep in mind when writing HQL queries is that domain class joins (HQL deals with domain classes, not tables) are completely reliant on the domain class associations. To put it differently, the associations actually create the (inner) joins, but HQL allows you to change the join type (LEFT OUTER, RIGHT OUTER, and Cartesian). See my from clause article.
I attempted to derive your domain class associations from your HQL and table descriptions and it just doesn't match up. But here's another way to do it.
Domain model
The domain model is very simple. There's a User class containing a one-to-many association to itself (but it's not a self-join, as you'll see in a moment).
class User {
String name
String lastName
static hasMany = [followees: User]
}
Lets say you have a User instance.
def user = User.get(1)
user.followees contains the Users being followed by user.
Table schema
With such a domain model the tables would look something like this:
user table
+------+--------+-------------+
| id | name | last_name |
+------+--------+-------------+
| 1 | John | Doe |
| 2 | Jane | Doe |
| 3 | Alfred | Hitchcock |
+------+--------+-------------+
user_followees table
+-----------+-------------------+
| user_id | followees_user_id |
+-----------+-------------------+
| 1 | 2 |
| 3 | 1 |
+-----------+-------------------+
The data demonstrated suggests that:
John Doe follows Jane Doe.
Jane Doe is followed by John Doe.
Alfred Hitchcock follows John Doe.
John Doe is followed by Alfred Hitchcock.
This simple one-to-many association can be used to model the two-way relationship that is known as following. The same could be done with two one-to-many associations, which would simplify querying but complicate data maintenance. With this model the two-way following relationships are maintained with a single user.addToFollowee() or user.removeFromFollowee().
Querying
Using the domain model I described, you can query for followees and followers. Given a user...
def followees = user.followees // <-- contains Jane Doe
def followers = User.executeQuery
'SELECT u FROM User as u INNER JOIN u.followees as followee WHERE followee = :user',
[user: user] // <-- contains Alfred Hithchcock
def following = followees + followers
Note that GORM/Hibernate does not support SQL's UNION clause, so you'll need two queries. See my where clause article for more details on GORM's equivalent of the where clause.
Followers
It's also possible to use a where or criteria query to get the followers:
def followers = User.where { followees.id == user.id }.list()
def followers = User.withCriteria { followees { eq 'id', user.id } }
Just for the sake of simplicity and since I was only reading data, I ended up using Groovy SQL which is accepted by Grails and itself accepts the plain SQL query I included in my original post (and doesn't require to match any specific domain model, big plus for me in this scenario)
Here's a link to the JavaDoc, I specifically used the rows(String sql, Map params) method definition to query de DB and return the data I was searching for.
For using groovy.sql.Sql in Grails, I recommend adding it as a bean to the resources.groovy file:
beans = {
groovySql(groovy.sql.Sql, ref('dataSource'))
}
and then inject the same into wherever you wanna use it:
class MyService {
def groovySql
...
def myMethod() {
String query = "SELECT * FROM user WHERE ..."
Map params = [param1: p1]
List<GroovyRowResult> result = groovySql.rows(query, params)
...
}
}
Hope this helps anyone trying to perform plain SQL queries without the hassle of having to convert them to HQL or Criteria.

stop repetition of column value in mysql

I have two tables related via id.
books:
book_id | book_name | year | publisher | slug
chapters:
chapter_id | book_id | chapter_name
Now when I query the database to find all the chapters related to a book like this:
SELECT book_name, chapter_name FROM ci_books, ci_chapters WHERE ci_books.book_id = ci_chapters.book_id AND slug = 'twelvers-dawn';
I get:
**book_name | chapter_name**
twelvers | Rising Sun
twelvers | Slow Down
twelvers | Masochist
I get the name of the book repeating with each chapter, how can I a stop the name from repeating so that only the name shows once and all the chapters are displayed?
You could use GROUP_CONCAT() like:
SELECT book_name, GROUP_CONCAT(chapter_name) as ChapterNames
FROM ci_books, ci_chapters
WHERE ci_books.book_id = ci_chapters.book_id AND slug = 'twelvers-dawn'
GROUP BY book_name;
See resource here
Use GROUP_CONCAT() with GROUP_BY
SELECT book_name, GROUP_CONCAT(chapter_name) AS chapter_names
FROM ci_books, ci_chapters
WHERE ci_books.book_id = ci_chapters.book_id AND slug = 'twelvers-dawn'
GROUP BY book_name;

Which method is better way to store information in table?

I am going to store user Likes into database. But I am not sure which one of these 2 methods is better:
in my situation, users can like Posts, Comments and Groups. something like Facebook.
Assume there are 10 million likes for : Posts, Comments and Groups
Method A:
Create a Like table, and add a LikeType field in it:
+--------+----------+--------+
| likeID | LikeType | userID |
+--------+----------+--------+
| 1 | 1 | 1 | // User 1 liked a post
+--------+----------+--------+
| 2 | 2 | 1 | // User 1 liked a comment
+--------+----------+--------+
| 3 | 3 | 1 | // User 1 liked a group
which LikeType includes : 1,2,3
1 = Posts, 2= Comments, 3= Groups
Method B:
Create three separated tables for each one of Posts, Comments and Groups.
in Method A,
Because there are too many likes and it needs an extra condition ( Where status = 1, or 2, or 3 ) to get a Post, Comment or Group likes, which method is better?
UPDATED POST:
users
uid // PK
---------------------------------------
itemTypes
typeID // PK
typeText // comments, groups, posts
---------------------------------------
--------------------------------------- +
posts |
id // PK |
typeID // 1 |
... |
--------------------------------------- +
comments |
id // PK |
typeID // 2 |
... |
--------------------------------------- + Items
groups |
id // PK |
typeID // 3 |
... |
--------------------------------------- +
photos |
id // PK |
typeID // 4 |
... |
--------------------------------------- +
---------------------------------------
likes
uid // FK to user id
itemid // FK to posts, groups, photos, comments id
itemType // FK to itemsTypes.typeID
// select post #50 likes
SELECT count(*) FROM likes WHERE itemid = 50 and itemType = 1
// select comment #50 of user #2
SELECT * FROM likes WHERE itemid = 50 and uid = 2 and itemType = 2
is this a good schema ?
I don't like either of your methods. I would go more normalized. I would have a table for item types, such as comments, groups, posts, etc. Then I would have a table for items. It would have an ItemId as the PK and a FK reference to item types. There would also be a users table. Finally, the likes table would be a many to many relationship between items and users.
As Jan Doggen said, what you're doing with the information is an important consideration. In particular, if you want to be able to ask the question "what things does a given user like", then you will benefit from having all the data in one table -- otherwise, you'd have to have three separate queries to answer that question.
For the case of the question "which people like a given thing", the performance difference between the single-table model and the multiple-table model should be relatively small if your tables are properly indexed (with an index on likeID/likeType, in this case). The multiple-table model will make your application logic more complex, and will be harder to extend in the future when you want to add other things a user might be able to like.

rails how to create record with id

I'm using rails v3.0.9 and Mysql database.
I'm migrating the tables with existing data.
I've users table and all other tables contains the user_id column and now i need seperate the users into two (users & customers) tables,
So i need to migrate the new customers table with existing users records where the user type with customer
I need to create a customers table and set the id of users records with user type as customer,
which will be easy instead of migrating many of other tables(which is used only by customers) by checking every record with user's user type and assign the new id of customers table.
Tables looks like
users table:
id | name | ...
------------------------------
1 | aaa | ...
2 | bbb | ...
4 | ddd | ...
6 | fff | ...
customers table
id | name | ...
-------------------------------
3 | ccc | ...
5 | eee | ...
7 | ggg | ...
When i'm migrating users existing data
In my migration file
def up
create_table(:customers) do |t|
t.string :name
end
User.joins(:user_type).where(:user_type => {:type_name => 'customer'}).find_in_batches(:batch_size => 100){ |users|
users.each {|user|
customer = Customer.new
customer.id = user.id
customer.name = user.name
customer.save(:validate => false)
}
}
end
Also tried
Customer.create!(:id => user.id) instead of save method
Is this correct?
Is there any way to assign the primary id ?
If i'm going wrong give me some suggestion to do it in right way...
Mysql allow to insert the record with value of primary id column.
In Rails, you can execute any sql query by supplying to execute method
For example:
sql = "insert into users(id, username) values(10, 'iam')"
ActiveRecord::Base.connection.execute(sql)