Laravel Eloquent select function cause empty relation - laravel

Following is my query
$user = User::select(['uuid','name','about'])->with(['education','work'])->first();
this returns empty data for relationship education and work,
but if I remove select function from query I am getting data in relationship and it also returns all columns of user table which I don't want.
how can solve this problem

The problem is that relationships (with(...)) execute an additional query to get the related results. Let's say you have one to many relationship where users have many works. User::with('work')->find(1) will then execute these 2 queries:
select user where id = 1 and select works where user_id = 1.
So basically in order to be able to execute the second query (fetch relationship data) you need to include id (or whichever column you're referencing) in you select statement.
Fix:
$user = User::select(['uuid','name','about', 'id'])->with(['education','work'])->first();
Same principle in different forms applies to all relationships. For example in the inverse of hasMany which is belongsTo you would need to select the foreign key (for example user_id).

Related

Laravel eloquent distinct select with possibility to call relation?

I want to select distinct results from one table, the structure is following:
id, user_id, category_id, last_answered_question_id
I have relation for last_answered_question_id called: lastAnsweredQuestion()
My query is:
Answer::select('category_id')->where(['user_id' => $userId])->distinct()->get();
This query works as expected but in this case I can't call relation $answer = lastAnsweredQuestion.
Is there any known way to get distinct items and call relation lastAnsweredQuestion() anyway?

Why Laravel does not make lots of queries when using exists on relations?

I have such entities as:
Company
Person
Company hasMany Persons. So in the persons table there is company_id column.
I return company list, which I pass to CompanyResource. There I return has_persons => $this->persons()->exists() value.
Then I checked the result of DB::getQueryLog() and I found out that there is only one SQL query, which does not have count or anything like that.
In order to count how many persons a company has, Laravel should make one query per company, shouldn't it? Like select count (*) from persons where company_id = 5 for example
try this
$this->persons->count()

In Laravel Eloquent, how do I reference primary query in subquery

I have a model User that has many Orders. Orders have many products, with the pivot table order-product. I don't want to preload and iterate through the orders if at all possible.
I need to return users where
signed_date === true on User
order_date on Order is after signed_date on User
order-product shows product hasn't been paid
I am failing on number 2.
In the following code, the first query within whereHas is wrong. I don't know how to reference the signed date of the user from within the where has. If I was iterating through users in a collection I could do something like ($query) use $user, but how do I do this without preloading all the users?
return User::whereNotNull('signed_date')
->whereHas('orders', function ($query) {
$query->where('order_date', '<=', 'user.signed_date');
$query->whereHas('products', function ($q) {
$q->where('paid', false);
});
})
->get(['id','fname','lname', 'title', 'signed_date']);
I would like to use eloquent if possible. If that is not possible, I would be happy for tips in solving this problem using the query builder/sql.
The Eloquent query builder has a special function called whereColumn('a', '<=', 'b') to compare columns instead of a column against a value. Using this function instead of a normal where() is necessary because of the way the query builder builds the actual query. You need to let the query builder know that you are going to pass a column name instead of a value for proper escaping and formatting of the query string.
Anyway, it seems you can also pass column names prefixed with a table name to the function, allowing you to compare columns across tables:
$query->whereColumn('orders.order_date', '<=', 'users.signed_date')
This works because you are using whereHas() in your query. Your query basically gets translated to:
SELECT id, fname, lname, title, signed_date
FROM users
WHERE signed_date NOT NULL
AND EXISTS (
SELECT 1
FROM orders
WHERE orders.order_date <= users.signed_date
AND EXISTS (
SELECT 1
FROM products
WHERE paid = 0
)
)
It might actually be not necessary at all to use the table name together with the column name in whereColumn(). But in case you'll ever add a column named the same on another table, the query might break - so IMHO it is good practice to use the table name in custom queries.
By the way, the reason this will not work together with with('relationship') is that this function results in an additional query and you obviously cannot compare columns across queries. Imagine the following:
Order::with('user')->take(5)->get();
It will be translated into the following:
SELECT *
FROM orders
LIMIT 5
SELECT *
FROM users
WHERE id IN (?, ?, ?, ?, ?)
where the five ? will be the user_ids of the orders. If the first query returns multiple rows with the same user_id, the amount of rows fetched from the users table gets reduced of course.
Note: All the queries are only examples. Might be that the query builder builds different queries based on the database type and/or escapes them differently (i.e. column names in backticks).

Is it possible to join eloquent relationship query?

I have a users, departments, and positions table.
I want to select one department with all the users in that department with their position name.
Currently, I have this.
$department = DepartmentView::with('users')
->findOrFail($departmentId);
It returns me a department with users, but I want to join the users with positions table so I can also get the position name. (user table only has position id)
Assuming you have your relationships setup properly in your User model and the relationship is called position, it should be like this:
$department = DepartmentView::with('users.position')
->findOrFail($departmentId);
Look at eager loading -> nested eager loading.
You can do
$department = DepartmentView::with('users.position')->findOrFail($departmentId)
position is referred to the relationship set on the User model to get the user position.

Eloquent Subquery

I have a many to many relationship between a student table and a apparatus table (A student performs on many apparatuses and an apparatus has many students). I have a student_results table that has a composite primary key (student_id and apparatus_id) and a 3rd field called results).
I have written a query to find all the apparatuses that a student DOES NOT have a result. The example I give is for student with id = 121.
The sub-query is.
SELECT apparatus_id, strapparatus_name FROM apparatuss
WHERE apparatus_id <> ALL(SELECT apparatus_id FROM student_results
WHERE student_id =' . 121 . ')';
I would like to write this using Eloquent (Laravel 4.1).
Any help greatly appreciated.
Assuming that you already have your Eloquent models Apparatus and StudentResult set, this is a way:
Apparatus::whereNotIn(
'apparatus_id',
StudentResult::where('student_id', 121)->lists('apparatus_id')
)->get('apparatus_id', 'strapparatus_name');
Or, if you don't have a model for your student_results table, you can just:
Apparatus::whereNotIn(
'apparatus_id',
DB::table('student_results')->where('student_id', 121)->lists('apparatus_id');
)->get(array('apparatus_id', 'strapparatus_name'));

Resources