Laravel eloquent deep count with relationship - laravel-5

I want to get count from deep table and the relationship is A->B->C->D and I want total count of D.
For example;
A: 3 Boss
B: 5 Managers
C: 8 Human Resources
D: 25 Employees
Imagine that every boss has managers and every manager has human resources and also every human resource has employees. How can I get total count every boss's employees' with Laravel. (For instance, first boss has 7 employees at the end.) Should I have to write hard sql code like joins or can I handle with eloquent?
By the way, my tables:
A: id, name
B: id, name
A and B has pivot table.
C: id, name
B and C has pivot table
D: id, name
C and D has pivot table
So far, I tried to:
$a = Boss::with("a.b.c.d")->where("id", 10)->first();
dd($a->b->c->d->count());
It just gave me d's count but I want to all of a's.

There is no native relationship for this case.
I created a HasManyThrough relationship with unlimited levels: Repository on GitHub
After the installation, you can use it like this:
class A extends Model {
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function d() {
return $this->hasManyDeep(D::class, ['a_b', B::class, 'b_c', C::class, 'c_d']);
}
}
$count = A::find($id)->d()->count();

Related

How to define the following relationship

I am developing a p2p app with laravel. I have two tables namely users and loans.
Firstly, a user can be a lender or borrower.
Then users can have multiple loans and multiple loans belong to multiple users.
Also, a loan can belong to one borrower and also to multiple lenders.
To explain it further, the loan record will be created by the borrower(or the user). Then the system will distribute the loan and assign it to multiple lenders.
Example: Let's say, one borrower wants a loan of 3000. Our system will distribute the loan as 2000 and 1000 (or 1500 and 1500, or 2500 and 500, etc.). Then assign it to two lenders.
Now it could be more lenders or bigger amounts.
So how can I define something like this with laravel eloquent?
Here's what I thought of till now.
Users and loans will have a many-to-many relationship.
Loans table will have a lender_data column which will be an array that contains lender_id and amount.
But I can't really figure out a way to fetch all the loans of a single lender. So how can I do that?
That's a lot of words. Thank you for reading.
First of all, this question is quite vague and doesn't show any code which I think all questions should. Its harder to answer questions like this that don't necessarily have predefined answers.
Personally, I'd look into intermediate table models:
https://laravel.com/docs/8.x/eloquent-relationships#defining-custom-intermediate-table-models
That way you can have a Lenders table, a Loan table, a Users table, and this "in between" table that could be something like a LoanAmount table. The LoanAmount table is mostly a pivot table (allowing the many to many relationship between Lenders and Loans), however it can also store data like:
loan_id lender_id amount
1 1 1000
1 2 1000
Then the loan table would just be
user_id amount
1 2000
So a User can have many Loans, but it's the Loans that can have many LoanAmounts.
I'd go with next:
class User extends Model
{
public function loans()
{
return $this->belongsToMany(Loan::class)->using(LoanUser::class)->withPivot(['amount', 'percentage']);
}
}
class Loan extends Model
{
public function users()
{
return $this->belongsToMany(User::class)->using(LoanUser::class)->withPivot(['amount', 'percentage']);
}
}
class LoanUser extends Pivot
{
protected $with = [
'landers',
];
public function landers()
{
return $this->belongsToMany(Lander::class)->withPivot(['percentage']);
}
}
class Lander extends Model
{
public function loanUsers()
{
return $this->belongsToMany(LoanUser::class)->withPivot(['percentage']);
}
}
In loan_user pivot table you should make field called percentage that will go to user from full amount. In second pivot between LoanUser and Lander lander_loan_user you should also need percentage field that you would assign to each lander_loan_user relation. It would be second pivot table data.
After you save loan_user data, you would need to attach landers to first pivot model (second pivot table doesn't require pivot model per description). Since there are eager loaded landers to pivot model, when you query some user and their loan
$user = User::where(['loan.amount' => 3000])->first();
$user->pivot->landers;// will get you related landers
You already have full amount in first pivot table and with percentage from same table you know how much user (borrower) gets and in pivot's relation to landers table you will know how much each lander gets from that loan.
It is like "T" relation where upper ends of 't' letter are Loan and User, that crossroad is LoanUser pivot and lower end (base) of the letter 't' are landers.
To avoid hard time as much as possible, keep up with eloquent's convention (check good practice here) and for example, instead of borrower_id call that loan_id, also pivot table to be loan_user (pay attention on pivot singular).
This was written from top of head and not tested but this is the idea/way how task can/should be finished.

Which way will get high performance while selecting many data IQueryable Vs For loop (Using Entity Frame Work)

I am trying to get a list from the database containing two or more lists inside that list.(using .net core, entity framework).Assume I have two table call header and details table.
Header Table
Detail Table
And I want the result like this:
{
"data":[
{
"Country":"Singapore",
"Hospital_List":[
{
"Hospital_Name":"SG Host A"
},
{
"Hospital_Name":"SG Host A"
}
]
},
{
}
]
}
I only know two ways to get the result like this,First Way, select Country list data with blank Hospital list as List,then for loop that list to select related Hospital list from db again.
And Second Way,select Country list data with blank Hospital list as IQueryable List,and then select related Hospital list via jointing with Hospital Table.So my question is
Which way should i used to get higher performance? And Is any other way?
Please remember there has a lot of field and data in my real table.
For loop give give you the lowest perfomance, because you will create SQL query for each iteration. Instead of this, try following solution:
from hospital in hospitals
group hospital by hospital.CID into gh
join country in countries
on gh.FirstOrDefault().CID equals country.CID
select new
{
Country = country.Country,
Hospital_List = from h in gh select h
}
EDITED:
And if your model created right you can use this code:
from hospital in hospitals
join country in countries
on hospital.Country equals country
group hospital by hospital.CID into gh
select new
{
Country = from h in gh select h.Country.Country,
Hospital_List = from h in gh select h
}

Laravel 5 hasManyThrough repeating row content

I have the following Database tables:
tour
idtour
other_columns
day
idday
other_columns
tour_has_day
idtour
idday
Each tour has many days, and the days can be used in other tours
So, in the Tour.php model I add this function:
function days () {
return $this->hasManyThrough('App\Day', 'App\Tour_has_day', 'idtour', 'idday');
}
It gives me the correct number of related days but all rows have the same content
I debug the query that it returns:
select
`day`.*,
`tour_has_day`.`idtour`
from `day`
inner join
`tour_has_day` on `tour_has_day`.`idtour` = `day`.`idday`
where
`tour_has_day`.`idtour` = '1'
And it returns
You'll need a many-to-many relation with a pivot table like the one you have for that. The has-many-through relation is for when you have a parent and a child, and the child is the parent of another child.

Relational algebra for one-to-many relations

Suppose I have the following relations:
Academic(academicID (PK), forename, surname, room)
Contact (contactID (PK), forename, surname, phone, academicNO (FK))
I am using Java & I want to understand the use of the notation.
Π( relation, attr1, ... attrn ) means project the n attributes out of the relation.
σ( relation, condition) means select the rows which match the condition.
⊗(relation1,attr1,relation2,attr2) means join the two relations on the named attributes.
relation1 – relation2 is the difference between two relations.
relation1 ÷ relation2 divides one relation by another.
Examples I have seen use three tables. I want to know the logic when only two tables are involved (academic and contact) as opposed to three (academic, contact, owns).
I am using this structure:
LessNumVac = Π( σ( job, vacancies < 2 ), type )
AllTypes = Π( job, type )
AllTypes – LessNumVac
How do I construct the algebra for:
List the names of all contacts owned by academic "John"
List the names of all contacts who is owned by academic "John".
For that, you would join the Academic and Conctact relations, filter for John, and project the name attributes. For efficiency, select John before joining:
πforename, surename (Contact ⋈academicNO = academicID (πacademicID (σforename = "John" Academic))))
You have to extend your operations set with natural join ⋈, Left outer join ⟕ and/or Right outer join ⟖ to show joins.
There is a great Wikipedia article about Relational Algebra. You should definitely read that one!

Efficient algorithm that takes a Twitter user and finds top users by order of how many of his followers they follow

The title is very wordy. So I'll explain with an example.
We have a database of 10,000 twitter users with each following up to 2000 users. The algorithm takes as input one random never before seen user (including the people that follow him), and returns the twitter users from the database by order of how many of his followers they follow.
i.e.
We have:
User A follows 1,2,3,4
User B follows 3,4,5,6
User C follows 4,8,9
We enter user X who has users 3,4,5 following him.
The algorithm should return:
B: 3 matches (3,4,5)
A: 2 matches (3,4)
C: 1 match (4)
Store the data as a sparse integer matrix A of size 10^5x10^5 with ones at the appropriate places. Then, given a user i, compute A[i,] * A (matrix multiplication). Then sort.
Assuming you have a table structure similar to this:
Table Users
Id (PK, uniqueidentifier, not null)
Username (nvarchar(50), not null)
Table UserFollowers
UserId (FK, uniqueidentifier, not null)
FollowerId (uniqueidentifier, not null)
You can use the following query to get the common parents of followers of the followers of the user in query
SELECT Users_Inner.Username, COUNT(Users_Inner.Id) AS [Total Common Parents]
FROM Users INNER JOIN
UserFollowers ON Users.Id = UserFollowers.FollowerId INNER JOIN
UserFollowers AS UserFollowers_Inner ON UserFollowers.FollowerId = UserFollowers_Inner.UserId INNER JOIN
Users AS Users_Inner ON UserFollowers_Inner.FollowerId = Users_Computed.Id
WHERE (UserFollowers.UserId = 'BD34A1FF-FCF5-4D35-B8A3-EFFB1587A874')
GROUP BY Users_Inner.Username
ORDER BY COUNT(Users_Inner.Id) DESC
would something like this work?
for f in followers(x)
for ff in followers(f)
count[ff]++ // assume it is initially 0
sort the ff-s by their counts
Unlike the matrix solution, the complexity of this is proportional to the number of people involved rather than the number of users on twitter.

Resources