I am trying to get a single column of an inner joined model.
$items = Item::with('brand')->get();
This gives me the whole brand object as well, but I only want brand.brand_name
$items = Item::with('brand.brand_name')->get();
DidnĀ“t work for me.
How can I achieve this?
This will get related models (another query) with just the column you want (an id, see below):
$items = Item::with(['brand' => function ($q) {
$q->select('id','brand_name'); // id is required always to match relations
// it it was hasMany/hasOne also parent_id would be required
}])->get();
// return collection of Item models and related Brand models.
// You can call $item->brand->brand_name on each model
On the other hand you can simply join what you need:
$items = Item::join('brands', 'brands.id', '=', 'items.brand_id')
->get(['items.*','brands.brand_name']);
// returns collection of Item models, each having $item->brand_name property added.
I'm guessing Item belongsTo Brand, table names are items and brands. If not, edit those values accordingly.
Try this:
$items = Item::with(array('brand'=>function($query){
$query->select('name');
}))->get();
Related
I have a list with messages. Its possible to reply to these messages (parent - child). I do not show child-messages in the list.
How can I always display the newest parent-message on top. Newest means that either the parent OR one of the childern has the newest timestamp.
Here is my eloquent query:
Message::withCount(['childMessages as latest_child_message' => function($query) {
$query->select(DB::raw('max(created_at)'));
}])
->orderByDesc('latest_child_message')
->orderByDesc('created_at')
->get();
Both orderBy should somehow be combined. Otherwise either the parent or the child sort will be prioritised.
In the context it's not possible to sort the collection after the DB-query.
edit 1:
Since "ee" is the latest response (child), the "bb" message should be at the bottom of the list.
edit 2:
The query will be used in a function returning a query
public static function getEloquentQuery(): Builder {
$query = parent::getEloquentQuery();
return $query->doTheMagicHere();
}
edit 3
This would be a working query.. but it's very slow
SELECT
id,
comment,
(SELECT MAX(cc.id) FROM comments cc WHERE cc.commentable_id = c.id) AS child_id
FROM
comments c
WHERE
commentable_type NOT LIKE '%Comment%'
ORDER BY CASE WHEN child_id IS NULL
THEN id
ELSE child_id
END DESC
;
In the withCount closure you must set conditions.
Use this:
Message::with('childMessages')->get()->sortByDesc(function ($parent, $key) {
$child = $parent->childMessages()->orderBy('created_at', 'desc')->first();
return $child ? $child->created_at : $parent->created_at;
});
the orderBy way you need is a bit complicated. it's better to use sortByDesc method and sort data on collection.
I hope this works.
In laravel 8, I am filtering blog articles by category. However when I select multiple categories in my select menu. I do get the proper request . for example: articles/category/?category_ids=3,4
But it will only output one selected filter. If I select 2 filters it just selects that next filter as if I only selected that one. (I also use Axios but the request is done proper, so its in my Controller)
Here is my code I tried:
$data['articles'] = Article::whereHas('categories', function ($query) use($category_ids){
$query->whereHas('category_id', '=', $category_ids)->where('premium',0);
;})->get();
I also tried:
$data['articles'] = Article::whereHas('categories', function ($query) use($category_ids){
$query->whereIn('category_id', [$category_ids])->where('premium',0);
;})->get();
So how do I get to query both or more category id's ?
I am using a pivot table:
Articles can have many Categories
Categories can have many Articles
I use article_category as a pivot table
When checking for relationship existence in many-to-many relations, the check is still to be done against the id in the categories table.
Try this
$category_ids = collect(explode(',', $request->category_ids))
->map(fn($i) => trim($i))
->all();
$data['articles'] => Article::whereHas('category', fn($query) =>
$query->whereIn('categories.id', $category_ids)
->where('categories.premium', 0)
)->get();
You can explode the categories and then make the query like this.
$categories = explode(',',$request->categories);
$data['articles'] = Article::whereHas('categories', function ($query) use($categories){
$query->whereIn('category_id', $categories)->where('premium',0);
})->get();
this is my situation:
I have a collection of products and i want all the categories of those products.
Between Product and Category there is a many-to-many relation already created, and i want to do something like this:
$prods = Product::where(something)->get();
$categories = $prods->categories();
But obviously this doesn't work, and i would avoid getting all categories for each products, and add it to a collection only if is not alredy in it... something like this:
select *
from categories join pivot on categories.id = pivot.id
where pivot.product_id IN (1,2,3,4,5)
where 1,2,3,4,5 are the ids of the products
Is there any way to do it without QueryBuilder (using Eloquent)?
You should define a many-to-many relationship in your Product model
public function categories()
{
return $this->belongsToMany(Category::class);
}
And then you can do this
$ids = [1,2,3,4,5];
$prods = Product::with('categories')->findOrFail($ids);
$categories = $prods->flatMap->categories;
The with call eager loads your categories, and then you retrieve them easily + flatten (to avoid multi-dimensional collection) thanks to flatMap method.
I have two related tables, posts and hidden_posts, where posts.id corresponds to hidden_posts.post_id.
In my posts model I have this relation to return a record if the post should be hidden:
public function getHiddenPosts()
{
return $this->hasOne(HiddenPost::className(), ['post_id' => 'id']);
}
Now I need to return all posts that are NOT hidden. So I am looking for the equivalent of this pseudo code:
return $this->hasNone(HiddenPost::className(), ['post_id' => 'id'])->all();
Which is saying, "show me all posts that are not in the hidden_posts table".
So does this use an outer join query or is there a statement that I can't find do do this in one line?
You can do it this way. Get all posts that are not listed in Hidden table:
$posts = Post::find()
->andFilterWhere(['not in',
'post.id',
HiddenPost::find()
->select(['hidden_post.post_id'])
->all();
In any case, it is best to proceed from the raw SQL statement. Write a statement that satisfies your results and transfer it to ActiveRecord query.
Post items could be retrieved using an inner join
$res = Post::find()
->select('post.*')
->innerJoin('hdn_post', '`post`.`id` = `hdn_post`.`post_id`')
->all();
It could be good practice using yii2 owned function instead of adding queries inside the model such as using select queries in your model.
Instead you can use ORM functions in yii2 has already done by gii inner functions created for to make u=your work easy.
Add * #property YourModel $hidden_post
and inside this model add you post_id such as ( * #property integer $post_id ) to create relation.
public function getHiddenPosts($hidden_post) {
return $this->find()->joinWith('hidden_post')
->where(['hidden_post' => $hidden_post])
->all();
}
You could retrive the Post items using an inner join
$posts = Post::find()
->select('post.*')
->innerJoin('hidden_post', '`post`.`id` = `hidden_post`.`post_id`')
->all();
for not hidden then use left join and check for null result of related table
$posts = Post::find()
->select('post.*')
->leftJoin('hidden_post', '`post`.`id` = `hidden_post`.`post_id`')
->where('ISNULL(`hidden_post`.console_id)')
->all();
Having two related tables, Car and CouponException, I wanna get all cars within an array of models and also get the CouponExceptions related to every Car, but the tricky thing comes here.. i only want to get the CouponException for that car given a coupon id. So what i'm trying now is:
$versions = Doctrine_Query::create()
->from('Car c, c.CouponException ce')
->whereIn('c.model', $models)
->addWhere('ce.coupon_id = ?', $cid)
->fetchArray();
But it only returns to me cars with a coupon exception, and what i want is get all cars in a model list and get the CouponException for that car if there is one with a given Coupon id...
I had to use the LEFT JOIN to get all results and use the "with" keyword to filter the second table.
$versions = Doctrine_Query::create()
->select('c.*, ce.*')
->from('Car c')
->leftJoin('c.CouponException ce WITH ce.coupon_id = '.$cid)
->whereIn('c.model', $models)
->fetchArray();
Now it works :))))