Where clause for arrays of single column in laravel - laravel

I'm building a small application on laravel 5.5 where I'm retrieving models with the relationship absence, something like this:
$milestone = Milestone::where('unique_id', $request->id)
->whereDoesntHave('block')
->first();
This is working fine but when I convert milestone variable to an array I'm getting absurd results, I tried:
$milestone = Milestone::where('unique_id', $request->id)
->whereDoesntHave('block', function ($q) use($request){
foreach($request->milestone as $m)
$q->where('unique_id', $m);
})
->first();
Edit:
Following is my relationship:
Milestone Model:
public function block()
{
return $this->morphMany('App\Models\Team\Block', 'block');
}
Block Model:
public function block()
{
return $this->morphTo();
}
and my block database table:
Schema::create('blocks', function (Blueprint $table) {
$table->increments('id');
$table->string('unique_id');
$table->string('block_type');
$table->integer('block_id');
$table->integer('generic_id');
$table->string('type');
$table->integer('user_id');
$table->timestamps();
$table->softDeletes();
});
Help me out in this, Thanks

You should use whereIn rather than a foreach with multiple where clauses. I.e.
$q->whereIn('unique_id', $mArray);
If you chain the where clauses together, those are AND where clauses. As an example
App\Models\User::where('id', 1)->where('id', 2)->toSql();
"select * from `users` where `id` = ? and `id` = ?"
App\Models\User::whereIn('id', [1,2])->toSql();
"select * from `users` where `id` in (?, ?)"
the former gives no results, while the latter gives the results you might expect

Chain whereDoesntHave():
$milestone = Milestone::where('unique_id', $request->id);
foreach($request->milestone as $m) {
$milestone = $milestone->whereDoesntHave('block', function ($q) use($m) {
$q->where('unique_id', $m);
});
}
$milestone = $milestone->first();
Or use whereHas() with whereNotIn():
$milestone = Milestone::where('unique_id', $request->id)
->whereHas('block', function ($q) use($request) {
$q->whereNotIn('unique_id', $request->milestone);
})
->first();

Related

filtering the most likes withcount not working

All the rest of the functionality works fine, follow and latest but for some reason it won't filter the likes. I think it is the count method, but if I do likes->count() I end up with too many queries, any solutions for this?
public function index(Request $request) {
$search = request()->input('title');
$posts = Post::query()->latest();
if ($search) {
$posts->where('title', 'LIKE', '%' . request()->title. '%');
} elseif ($request->has('likes')) {
$posts->withCount('likes')->orderByDesc('likes_count');
} elseif ($request->has('latest')) {
$posts->orderByDesc('created_at');
} elseif ($request->has('follow')) {
$posts->whereIn('user_id', $request->user()->following()->pluck('users.id'));
}
return view('welcome', [
'posts' => $posts->withCount(['comments', 'likes'])->paginate(12)
]);
}
Schema::create('likes', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->foreignId('post_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
This is the issue
$posts = Post::query()->latest();
"->latest()" is already sorting by date.
If you take it out, it should work just fine.

I am getting data from my database using Datatable, but it takes too much time to load

I am getting data from products table, i have use paginate in datatable which shows only 50 records first time, and when pager update to 200 rows it takes 12 to 13sec. Here is my Code. Thanks in Advance
$query = Product::query();
$query->with('def_or_last_supplier','units','prouctImages','productType',
'productBrand','productSubCategory',
'supplier_products','productCategory')
->where('status',1)->orderBy('refrence_no', 'DESC');
if($request->default_supplier != '')
{
$supplier_query = $request->default_supplier;
$query = $query->whereIn('id', SupplierProducts::select('product_id')->where('supplier_id',$supplier_query)->pluck('product_id'));
}
if($request->prod_type != '')
{
$query->where('type_id', $request->prod_type)->where('status',1)->orderBy('refrence_no', 'DESC');
}
if($request->prod_category != '')
{
$query->where('category_id', $request->prod_category)->where('status',1)->orderBy('refrence_no', 'DESC');
}
if($request->filter != '')
{
if($request->filter == 'stock')
{
$query = $query->whereIn('id',WarehouseProduct::select('product_id')->where('current_quantity','>',0.005)->pluck('product_id'));
}
elseif($request->filter == 'reorder')
{
$query->where('min_stock','>',0);
}
}
Your query isn't that big but I think maybe result data size is a bit big
so what you can do is:
1: in my experience is to try to select your relations fields too you can do that like so
Source
Product::with('def_or_last_supplier',
'units:id,created_at,updated_at', // Just add :field_1,field_2,another_field
'prouctImages:id,field_1,field_2'
....
)
2: I suggest you to take advantage of lazy loading. if it's possible don't eager load all your relations at once load them where it's needed
Source
$products = Product::get()
In blade or somewhere in application
under a special condition I need to access to my relation, I can easily do that by
$products->load('my_relation_name')
3: I see a lot of orderyBy clauses in your code, what you can do is to index the fields that are searchable or needs to be ordered. it can be done by adding ->index() in your migration file
Source
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('refrence_no')->index();
$table->timestamps();
});
}
4: and finally you can always try to cache your queries to prevent unnecessary queries to database, this is how cache works
source
$products = Cache::remember('cache_name', $how_long_in_seconds, function () {
return Product::get();
});
And finally here is the eloquent way of your query
$query = \Cache::remember(json_encode($request->toArray()), 300, function () use ($request) {
return Product::with('def_or_last_supplier',
'units',
'prouctImages',
'productType',
'productBrand',
'productSubCategory',
'supplier_products',
'productCategory'
)
->where('status', 1)
->orderByDesc('refrence_no')
->when($request->filled('default_supplier'), function (Builder $query) use ($request) {
$productIds = SupplierProducts::select('product_id')->where('supplier_id', $request->input('default_supplier'))->pluck('product_id');
$query->whereIn('id', $productIds);
})->when($request->filled('prod_type'), function (Builder $query) use ($request) {
$query->where('type_id', $request->input('prod_type'))->where('status', 1)->orderByDesc('refrence_no');
})->when($request->filled('prod_category'), function (Builder $query) use ($request) {
$query->where('category_id', $request->input('prod_category'))->where('status', 1)->orderByDesc('refrence_no');
})->when($request->filled('filter'), function (Builder $query) use ($request) {
$query->when('stock' === $request->input('filter'), function (Builder $query) {
$query->whereIn('id', WarehouseProduct::select('product_id')->where('current_quantity', '>', 0.005)->pluck('product_id'));
})->when('reorder' === $request->input('filter'), function (Builder $query) {
$query->where('min_stock', '>', 0);
});
})->get();
});

Return Related Books in Laravel

I want to return a book related to a book using the author's name
I have this function in my Controller
public function show(Book $book) {
$book = Book::where('id', '=', $book)->first();
$related = Book::whereHas('author_id', function ($q) use ($book) {
return $q->whereIn('name', $post->author->pluck('id'));
})
->where('id', '!=', $book->id) // So I won't fetch same post
->get();
return view('book')
->with($book)
->with($related);
}
This is the way my book table looks like
public function up()
{
Schema::create('books', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->text('about');
$table->string('image');
$table->string('image_url');
$table->string('epub_url');
$table->integer('author_id');
$table->string('publisher');
$table->year('year');
$table->boolean('recommended')->default(0);
$table->timestamps();
});
}
I have done this in my models
public function books()
{
return $this->hasMany(Book::class);
}
In Bookmodel
public function author()
{
return $this->belongsTo(Author::class);
}
I have done this, and this is not working for me, as I don't know what I am doing wrong. Thanks.
Once you have your $book, you can easily load other books by the same author by querying the author_id field. Just make sure to exclude the original book from the query, and you're good to go.
$relatedBooks = Book::where('author_id', $book->author_id)
->where('id', '!=', $book->id)
->get();
As a side note, you're already passing an instance of Book in your method arguments, so the first line of your code ($book = Book::where('id', '=', $book)->first();) is redundant, you can simply use $book.
You are querying the wrong way. what you can do is first get the book with author as given,
$book = Book::with(['author'])->where(['id' => $BOOK_ID])->first();
then you can load the similar books from the same authors as given
$similarBooks = Book::whereHas('author' => function($query) use ($book){
$query->where(['id' => $book->author->id]);
})->where('id' , '!=' , $book->id)->get();
Alternatively you can load by the author's name by replacing the relation's query.

Incorrect result when trying to get rows to sort by date

I have custom code to get users ordering by updated_at column:
$customers = \App\Customer::whereHas('user', function ($query) {
$query->orderBy('updated_at', 'DESC');
})->get();
Table scheme:
Schema::create('customers', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('user_id');
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
$table->string('name')->nullable();
$table->string('lastname')->nullable();
$table->string('surname')->nullable();
$table->text('about')->nullable();
$table->timestamps();
});
You can see here query result. Why I get wrong result or my query is incorrect?
Assuming that you want to sort your customers and not the user relation you have to use orderBy on the Customer result:
$customers = \App\Customer::whereHas('user')
->orderBy('updated_at', 'DESC')
->get();
And as you do not want to order the users you don't need to use whereHas(). A simple has() should be fine:
$customers = \App\Customer::has('user')
->orderBy('updated_at', 'DESC')
->get();
try this query:
$customers = \App\Customer::whereHas('user', function ($query) {
$query->orderBy('users.updated_at', 'DESC');
})->get();
Actually I suspect you're trying to retrieve the relationship as well in order. You need to eager load, order by and use has:
$customers = \App\Customer::with(['user' => function ($query) {
$query->orderBy('updated_at', 'DESC');
})->whereHas('user')->get();
This should get the relationship and filter out all customers who don't have a user.
Try this query, maybe it works for you:
$query = App\Customer::join('users as user', 'user.id', '=', 'customers.user_id')
->orderBy('user.updated_at', 'desc')
->select('customers.*')->get();

Include the name of my interlocutor in my query (messaging system)

I've a messaging system (1v1) on my website and I want to join some informations about my interlocutor (name, avatar, etc.).
My structure is more than common:
Threads:
Schema::create('threads', function (Blueprint $table) {
$table->increments('id');
//...
});
Participants:
Schema::create('participants', function (Blueprint $table) {
$table->increments('id');
$table->integer('thread_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->foreign('thread_id')->references('id')->on('threads')->onDelete('cascade');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
To get my Threads I've this query:
Thread::select(
'users.name',
'threads.id',
//...
)->join('participants', 'participants.id', '=', 'threads.id')
->join('users', 'users.id', '=', 'participants.user_id')
->where('participants.user_id', '=', $user->id)
->get();
Of course, because of my where condition, it's my name and not the name of my interlocutor. How can I join the informations of my interlocutor and "exclude" mine?
PS: Please don't give me a messaging system package. I want to code it myself.
Edit:
Relation in my model Thread :
public function users()
{
return $this->belongsToMany('App\User', 'participants', 'thread_id', 'user_id');
}
public function participants()
{
return $this->hasMany('App\Participant', 'thread_id', 'id');
}
Edit 2:
#Jonas Staudenmeir code:
$threads = Thread::select(
'threads.id',
'threads.last_sender',
'threads.is_read',
'threads.last_message',
'threads.date'
)->whereHas('users', function($query) use($user) {
$query->where('users.id', $user->id);
})->with('users')->get();
foreach($threads as $thread) {
$interlocutor = $thread->users->where('users.id', '!=', $user->id)->first();
}
Trying to get the fields I only need:
$threads = Thread::select(
'threads.id',
'threads.last_sender',
'threads.is_read',
'threads.last_message',
'threads.date'
)->whereHas('users', function($query) use($user) {
$query->select('users.id') // May be its gonna run faster
->where('users.id', $user->id);
})->with('users')->get();
foreach($threads as $thread) {
$interlocutor = $thread->users->select(
'id',
'name',
...
)->where('users.id', '!=', $user->id)->first();
}
$intercolutor give me this error : Method Illuminate\Database\Eloquent\Collection::select does not exist.
Try this:
$threads = Thread::select('id', 'last_sender', 'is_read', 'last_message', 'date')
->whereHas('users', function($query) use($user) {
$query->where('users.id', $user->id);
})
->with('users:users.id,name,avatar')
->get();
foreach($threads as $thread) {
$interlocutor = $thread->users->where('id', '!=', $user->id)->first();
}

Resources