If I wanted to JOIN two tables I could do this:
$books = App\Book::with('author')->get();
The problem with that is that the results are kinda nested. eg. If I wanted to get the DOB of the author I'd have to do this:
foreach ($books as $book) {
echo $book->author->dob;
}
But what if I, instead, wanted to be able to do this?:
foreach ($books as $book) {
echo $book->dob;
}
How might I go about doing that? I suppose there could be a conflict dob was a column in the book table and the author table and that doing author_dob would be better but let's assume there isn't a conflict.
I guess a view could do the trick but is there a way to do that in Laravel without having to create a view?
$books = DB::table('books')
->join('authors', 'authors.id', '=', 'books.author_id')->get()
Actually you can do the same using eloquent. This way, you'll have access to all functions and extra parameters in your Book model file
App\Book::join('authors', 'authors.id', '=', 'books.author_id')->get()
You might want to use leftJoin() instead of join()
Related
So i have a query where i want to select specific columns and relation count on a model.
Something like this
$posts = Post::withCount('comments')->select('title', 'content')->get();
foreach ($posts as $post) {
$post->comments_count // this is not available because of select in query
}
Now when I use select in the query comments_count is no longer available. There is $appends option on the model where I can do something like $appends = ['comments_count'] on the Post model but it will not work. Any idea how to append the data and use the select on model while querying using eloquent.
there is $withCount option on the model as well but it will lazy load while querying comments with post (i.e. inverse relation query).
The problem if that withCount('comments') will generate the comments_count for each post.
Also, the select() overrides the previous withCount(). Simply change the order.
$posts = Post::select('title', 'content')->withCount('comments')->get();
foreach ($posts as $post) {
echo $post->comments_count;
}
If you want the global count, you'll need to use a collection method to sum all the counts.
echo $posts->sum('comments_count');
I have two tables, products and product_images, now I want to show product which has at least one image.
In controller I have a simple function in ProductController to fetch all the products:
public function products(){
$allProducts = $this->product->paginate(15);
return view('frontend.pages.products',compact('allProducts'));
}
But, I want to send the products which has at least one image of each product.
What should I do to achieve that?
Edit:
I have created relationship between tables, now how can I get my desired answer?
I have written this in the Controller:
$allProducts = $this->product->whereHas('product_images', function ($query){
$query->where();
})->get();
Assuming table schema
product
-id
-name
product_image
-id
-product_id
-url //any columns you needed
$product_ids = DB::table('product')
->join('product_image','product_image.product_id','=','product.id')
->select('product.id','roduct.name')
->groupBy('product.id')
->get();
$product_count = count($product_ids);
Eloquent has this built in.
Example
// Retrieve all posts that have three or more comments...
$posts = App\Post::has('comments', '>=', 3)->get();
In your case
In your case you could change the $allProducts line to be
$allProducts = $this->product()->has('product_image', '>=', 1)->paginate(15);
I didn't test the code above.
See documentation for more information on this topic.
https://laravel.com/docs/6.x/eloquent-relationships#querying-relationship-existence
You can use selectRaw:
$products = Product::leftJoin('product_images',function ($join){
$join->on('products.product_id','=','product_images.product_id');
})->selectRaw("products.product_id i, count(product_images.id) c")
->groupBy('products.product_id')
->where('c','>=',3)
->get();
Getting answer querying realtionship:
The query will look like following:
$allProducts = $this->product->has('Images')->paginate(15);
But, make you sure you have created relation in Model like the following:
public function Images(){
return $this->hasMany('\App\Models\ProductImages');
}
I have used hasMany relationship because one product can have multiple images.
My database structure is the following:
So I've got a Bloggers table (sorry for the typo in the image), which has 3 topic fields, all 3 are foreign keys to the topics' table id.
I made a Blogger view front-end with a simple table showing all blogger columns. At the moment, the id's of the topics are being shown instead of the names though.
How can I change this?
I've already tried the following in my Controller, but that just creates duplicates in the view with different values in the main_topic column.
$bloggers= DB::table('bloggers')
->join('topics', function ($join) {
$join
->on('bloggers.main_topic', '=', 'topics.id')
->orOn('bloggers.subtopic1', '=', 'topics.id')
->orOn('bloggers.subtopic2', '=', 'topics.id');
})
->select('bloggers.*', 'topics.name as main_topic')
->get();
return view('pages.bloggers', compact('bloggers'));
The answer to my specific question was a little different from the answers given, so I'll post it here in case anyone needs it in the future.
So I've got 3 tables: bloggers, topics and a pivot table called blogger_topic. bloggers contains 3 foreign keys (integers) to topics called main_topic, subtopic1, subtopic2. The pivot table contains a blogger_id, and a topic_id.
What I ended up with:
Blogger.php model:
public function mainTopic()
{
return $this->belongsTo('App\Models\Topic', 'main_topic', 'id');
}
public function subtopicOne()
{
return $this->belongsTo('App\Models\Topic', 'subtopic1', 'id');
}
public function subtopicTwo()
{
return $this->belongsTo('App\Models\Topic', 'subtopic2', 'id');
}
Topic.php model:
public function bloggers()
{
return $this->belongsToMany('App\Models\Blogger');
}
View (blogger.blade.php):
#foreach($bloggers as $blogger)
{{ $blogger->mainTopic }}
{{ $blogger->subtopicOne }}
{{ $blogger->subtopicTwo }}
#endforeach
I think you should change your database tables if possible as below (sample link), by creating a pivot table. And then I think you should make relationships in Blogger and Topic model files with many-to-many. Then it would be very easy to fetch all related topics. For eg,
$topics = $blogger->topics;
Here you can reference the sample db table designs
I kindly recommend you to use models in Laravel coz they'll make your life more simple. Hope this help.
If you cant change your database, you could use group_concat on the results. Not sure if it will work but something like:
DB::table('bloggers')
->join('topics', function ($join) {
$join
->on('bloggers.main_topic', '=', 'topics.id')
->orOn('bloggers.subtopic1', '=', 'topics.id')
->orOn('bloggers.subtopic2', '=', 'topics.id');
})
->groupby('bloggers.id')
->select('bloggers.*', 'topics.name as main_topic', DB::raw('group_concat(topics.name)'))
->get();
I have a USER table, an ITEMS table, and a LIKES table. I'm randomly taking 9 items from the Items table (which is named 'categories') and I want to get an array of users which liked that item. I'm returning a JSON response so I can't use laravel's ORM relationships as far as I know. I want to be able to look through the results (with javascript) like so:
foreach item
item->price
....
foreach user
(this is how i wish to look through the users with js)
endforeach
endforeach
{{--Im trying to get an output that looks like so--}}
0: {
cost: 409
views: 0
...
user_like_id: {1,5,2,4,5}
}
EDIT: This is what I would like to attach the array to...
$likes = Category::orderByRaw("RAND()")
->leftJoin('likes', 'likes.item_id', '=', 'categories.id')
->take(9)
->get();
I'm relatively new to programming so please dont downnrate this question
Laravel provides in ways to make json from objects. The first and simplest is the eloquent toJson() method:
$likes = Category::orderByRaw("RAND()")
->leftJoin('likes', 'likes.item_id', '=', 'categories.id')
->take(9)
->get()
->toJson();
$likes is now json.
Second method:
If you return a model from a controller or a routecallback function, laravel returns it as json. So:
class MyController extends Controller{
public function getIndex(){
return Category::orderByRaw("RAND()")
->leftJoin('likes', 'likes.item_id', '=', 'categories.id')
->take(9)
->get();
}
}
This example returns a json response which is quite usefull!
I actually got exactly what I wanted with this:
$likes = Category::orderByRaw("RAND()")
->take(9)
->with(array('getLikes' => function($query)
{
$query->with('getUser');
}))
->get();
Works exactly how I want ito :) thanks for the suggestion tho
I've got a situation where I've got Posts, Users and Comments.
Each comment stores a post_id and a user_id. What I want to do is get all of a user's comments on a particular post, so that I can do a call like this:
$comments = Auth::User()->comments(post_id=x)->text
(where I know what x is)
I have:
User->HasMany(comments)
Comments->HasOne(User)
Comments->HasOne(Project)
Project->HasMany(comments)
I feel like there needs to be a where or a has or a wherehas or something thrown in.. the best I can manage is that I pull Auth::User()->comments into an array and then search through the array until I find the matching post ID.. that seems wasteful.
with doesn't apply any join, so you can't reference other table.
You can use this:
// User model
public function comments()
{
return $this->hasMany('Comment');
}
// Comment model
public function scopeForPost($query, $postId)
{
$query->where('post_id', $postId);
}
// then you can do this:
Auth::user()->comments()->forPost($postId)->get();
Alternatively you can eager load comments with constraint:
User::with(['comments' => function ($q) use ($postId) {
$q->where('post_id', $postId);
}])->find($someUserId);
// or exactly the same as above, but for already fetched user:
// $user .. or
Auth::user()->load(['comments' => function ($q) use ($postId) {
$q->where('post_id', $postId);
}]);
// then you can access comments for $postId just like this:
Auth::user()->comments; // collection
When you need to filter your relations, you just have to do it in your Eloquent query:
$data = User::with('posts', 'comments')
->where('users.id', Auth::User()->id)
->where('posts.id', $postID)
->get();
Then you can
foreach($data->comments as $comment)
{
echo $comment->text;
}
Your Comments table would have foreign keys Post_Id and User_ID
To Access all the comments of a particular post from a particular user , can you try this way?
Comment::select('comments.*')
->where('comments.user_id', Auth::user()->id)
->leftJoin('posts','posts.id','=','comments.post_id')
->leftJoin('users','users.id','=','comments.user_id')
->get();
Am sure there is better way to achieve it, but this should give you desired results.
Note use aliases if you have conflicting column names
Let me know if this worked.