Count data slow use relationship in laravel? - laravel

$user = User::select(['id', 'name'])
->withCount([
'posts as success' => function ($query) {
$query->where('status', 0);
},
'posts as error' => function ($query) {
$query->whereIn('status', [1, 2, 3]);
},
])
->where('order', 3)
->get();
Model Post.php:
public function users() {
return $this->belongsTo(User::class);
}
Model User.php :
public function posts() {
return $this->hasMany(Post::class);
}
I want to count status in the post table through relationship. Like the above code, I got the result I wanted. But it is very slow, about 10 seconds or more. Is there any way to fix it? My post table has 400,000 data
I have index the status column in the post table.

Related

Laravel pass value from query to with() function

Here is my query:
$fix = Fixture::select('fixtures.*')
->whereDate('kickoff', '<', $date)
->with('competition')
->with('teamA')
->with(['teamA.standing' => function ($q) {
$q->whereColumn('standings.competition_id', '=', {{here i want the competition_id from competitions or fixtures table}} );
}])
->with('teamB')
->with(['teamB.standing' => function ($q) {
$q->whereColumn('standings.competition_id', '=', {{here i want the competition_id from competitions table or fixtures table}});
}])->get();
Code from Fixture model:
public function teamA()
{
return $this->belongsTo(Team::class,'team_a','id');;
}
public function teamB()
{
return $this->belongsTo(Team::class,'team_b','id');;
}
Code from Team model:
public function standing()
{
return $this->hasOne(Standing::class);;
}
Code from Standing model:
public function team(){
return $this->belongsTo(Team::class);
}
public function competition()
{
return $this->belongsTo(Competition::class);
}
Can someone help me to get this done or if I am doing it wrong what's the correct way?
->with(['teamA.standing' => function ($q) {
$q->whereColumn('standings.competition_id', '=', {{here i want the competition_id from competition table or fixtures table}} );
}])
Example:
Category::select('id', 'name')->whereHas('statuses', function($query) { $query(); })->with('courses')->get();

creating a section for test where registered users can do it, but currently the test can be done many times and I wish they could only do it once

I'm using laravel 7
I need that if the user already took the test, load another different view
This is my test controller
public function index()
{
$categories = Category::with(['categoryQuestions' => function ($query) {
$query->orderBy('id')
->with(['questionOptions' => function ($query) {
$query->orderBy('id');
}]);
}])
->whereHas('categoryQuestions')
->get();
return view('client.test', compact('categories'));
}
public function store(StoreTestRequest $request)
{
$options = Option::find(array_values($request->input('questions')));
$result = auth()->user()->userResults()->create([
'total_points' => $options->sum('points')
]);
$questions = $options->mapWithKeys(function ($option) {
return [$option->question_id => [
'option_id' => $option->id,
'points' => $option->points
]
];
})->toArray();
$result->questions()->sync($questions);
return redirect()->route('client.results.show', $result->id);
}
}
This is the way the result table connects to the user table
This my migration to add relationship with a users table;
class AddRelationshipFieldsToResultsTable extends Migration
{
public function up()
{
Schema::table('results', function (Blueprint $table) {
$table->unsignedInteger('user_id');
$table->foreign('user_id', 'user_fk_773765')->references('id')->on('users');
});
}
}
Update your index method to check the results table. Assuming you have a Result model, for your results table.
public function index()
{
$existingTest = Result::where('user_id', Auth::user()->id)->first();
if(isset($existingTest->id)) {
//Return your other view or run logic specific to if the user has already done the test.
return view('client.test-complete');
}
$categories = Category::with(['categoryQuestions' => function ($query) {
$query->orderBy('id')
->with(['questionOptions' => function ($query) {
$query->orderBy('id');
}]);
}])->whereHas('categoryQuestions')
->get();
return view('client.test', compact('categories'));
}

Laravel combine multiple scope

I have a posts table and every post can have 0, 1 or more rows into channels (table channels with post_id in it).
The posts table also has a a privacy field set to 0, 1 or 2.
I want to list specific posts so I defined scopes inside the Post model:
public function scopeNonPrivate($builder)
{
return $builder->where(function ($q) {
$q->where('post_privacy', '!=', Post::PRIVACY_ME);
$q->where('user_id', '!=', auth()->id());
})->orWhere(function ($q) {
$q->where('post_privacy', '=', Post::PRIVACY_ME);
$q->where('user_id', '=', auth()->id());
});
}
public function scopeNonZero(Builder $builder)
{
return $builder->whereHas('channels', function ($query) {
$query->where('channel_id', '!=', 0);
})->orWhereDoesntHave('channels');
}
public function scopeFromFriends(Builder $builder, $friends)
{
return $builder->whereIn('user_id', $friends);
}
I want to combine these scopes to that I can find all post fromFriends, which have a channel different from 0 or which do NOT have a channel, and with the privacyOnlyFriends.
When I combine these the result is not correct, this is what I do:
$post = Channel::find(1)
->posts()
->fromFriends([$friends->pluck('user_id'), $friends->pluck('friend_id')])
->nonZero()
->nonPrivate();
I defined in App\Channel:
public function posts()
{
return $this->belongsToMany(Post::class, 'post_channels', 'channel_id', 'post_id');
}
And I defined in App\Post:
public function channels()
{
return $this->belongsToMany(Channel::class, 'post_channels', 'post_id', 'channel_id');
}
Is there a way to keep data from the different scopes and merged together so that for example fromFriends() does not override nonPrivate() but they are merged?
You can combine multiple scopes, below is an example from my class:
public function scopeGetCommentsOn($queryBuilder, $table, $tableIdentifier)
{
return $queryBuilder->where('table_name', $table)
->where('table_identifier', $tableIdentifier);
}
public function scopeCommentsOnShipments($queryBuilder, $tableIdentifier)
{
return $queryBuilder->getCommentsOn('shipments', $tableIdentifier);
}
In the above example, I am using scope getCommentsOn in commentsOnShipments scope.
Hope this will help you.

Laravel : Search Query Within Relationship

When I am adding a new post in my app there is a 7 tables to affect when I add single post. To fetch all posts with all post data my simple query look like:
$userPost = Post::with(['product','postattribute.attribute.category','user.userDetails'])
->offset($offset)
->limit($limit)
->whereStatus("Active")
->whereIn('product_id', $userApprovalProductIDs)
->orderBy('id','desc')
->get();
So it is retrun all data which I want. Now I want to implement search query within all tables, currently I am able to search only posts table.
If I am doing search on category table with categoryTitle I am trying to code like
where('category.title','=', $serachTitle)
But it is not working in my case.
POST model relationship :
public function user() {
return $this->belongsTo(User::class);
}
public function product() {
return $this->belongsTo(Product::class);
}
public function postattribute() {
return $this->hasMany(PostAttribute::class);
}
POSTATTRIBUTES model relationship :
public function post() {
return $this->belongsTo(Post::class);
}
public function attribute() {
return $this->belongsTo(Attribute::class);
}
ATTRIBUTES model relationship :
public function category() {
return $this->belongsTo(Category::class);
}
public function attributes() {
return $this->belongsTo(Attribute::class);
}
How can I do this ?
To apply filter on your nested relations you could use whereHas
$userPost = Post::with(['product','postattribute.attribute.category','user.userDetails'])
->offset($offset)
->limit($limit)
->whereStatus("Active")
->whereIn('product_id', $userApprovalProductIDs)
->whereHas('postattribute.attribute.category', function ($query) use($serachTitle) {
$query->where('title', '=', $searchTitle);
})
->orderBy('id','desc')
->get();
Querying Relationship Existence
From comments what i understood is you want to know how to search within each relation for a post , I already added an example to search with category title
->whereHas('postattribute.attribute', function ($query) use($var) {
$query->where('some_field_of_attribute_table', '=', $var);
})
->whereHas('postattribute', function ($query) use($var) {
$query->where('some_field_of_postattribute_table', '=', $var);
})

Eloquent hasMany filter and eager loading

I'm creating an application with Laravel and I'm trying to work with Eloquent. I have two tables : Orders and Items.
Each items has a type (int data) :
1 => book
2 => video
Each order has ONE book and many videos.
In my Order model, I would like to have a book and others items relationships. So, I have this code :
public function book()
{
return $this->hasMany('App\Item')->where('type', 1)->first();
}
public function others()
{
return $this->hasMany('App\Item')->where('type', '!=', 1)->get();
}
But, if I use eager loading with my relationship, I got an error :
Order::with(['book', 'others'])->get();
Can you help me to solve this problem ?
Thanks
Define relationships like this to make your code work:
public function book()
{
return $this->hasOne('App\Item')->where('type', 1);
}
public function others()
{
return $this->hasMany('App\Item')->where('type', '!=', 1);
}
But it's better to define relationships without where constraints:
public function book()
{
return $this->hasOne('App\Item');
}
public function others()
{
return $this->hasMany('App\Item');
}
And then do this:
Order::with(['book' => function ($q) {
$q->where('type', 1);
},
'others' => function ($q) {
$q->where('type', '!=', 1);
}])
->get();

Resources