I am using Laravel 5.4
I have 3 models: Order, OrderLine and Product.
Order hasMany() OrderLines
OrderLine hasOne() Product via the product_id in the OrderLine model (I have properly indexed this, at least I think!)
My requirement is to retrieve all Orders and OrderLines where the Product is for a certain brand name.
Here is my eloquent query. I know the query works but it seems to infinitely run when put on a large dataset (circa 10,000 Orders, 12,000 OrderLines/Products)
$orders = Order::whereBetween('order_date', [$this->start_date,$this->end_date])
->whereHas('lines', function ($q1){
$q1->whereHas('product', function ($q2){
$q2->where('brand', 'Brands>SanDisk');
});
})->with('lines')->with('lines.product')->get()->toArray();
This produces the following SQL when debugging via toSql() method.
select
*
from `orders`
where
`order_date` between ? and ?
and
exists (select * from `order_lines` where `orders`.`id` =`order_lines`.`order_id`
and
exists (select * from `products` where `order_lines`.`product_id` = `products`.`id` and `brand` = ?))
My 3 migrations to create the tables are as follows (I have removed anything except keys for simplicity):
Schema::create('orders', function (Blueprint $table) {
$table->increments('id');
});
Schema::create('order_lines', function (Blueprint $table) {
$table->increments('id');
$table->integer('product_id');
$table->integer('order_id');
});
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
});
I then added the following index:
Schema::table('order_lines', function (Blueprint $table) {
$table->integer('product_id')->unsigned()->change();
$table->foreign('product_id')->references('id')->on('products');
});
Results of EXPLAIN syntax as follows:
1 PRIMARY orders ALL 91886 Using where
2 DEPENDENT SUBQUERY order_lines ALL 93166 Using where
3 DEPENDENT SUBQUERY products eq_ref PRIMARY PRIMARY 4 mymemory_main.order_lines.product_id 1 Using where
Try this:
mpyw/eloquent-has-by-non-dependent-subquery: Convert has() and whereHas() constraints to non-dependent subqueries.
mpyw/eloquent-has-by-join: Convert has() and whereHas() constraints to join() ones for single-result relations.
$orders = Order::query()
->whereBetween('order_date', [$this->start_date, $this->end_date])
->hasByNonDependentSubquery('lines.product', null, function ($q) {
$q->where('brand', 'Brands>SanDisk');
})
->with('lines.product')
->get()
->toArray();
That's all. Happy Eloquent Life!
Related
I want to built many to many polymorphic relations Table structure. Choosen categorizables table is pivot. I am creating a table like the one below but I can not be sure of the correctness.
blogs
id - integer
name - string
...
videos
id
video_url
categories
category_id - integer
name - string
categorizables
category_id - integer - unsigned
categorizable_id - integer -unsigned
categorizable_type - string - nullable (value likes 'App\Blog' )
Following code belongs to the categorizables table.
public function up()
{
Schema::create('categorizables', function (Blueprint $table) {
$table->unsignedInteger('category_id');
$table->unsignedInteger('categorizable_id');
$table->string('categorizable_type');
$table->timestamps();
$table->index(['category_id', 'categorizable_id']);
$table->index(['categorizable_id', 'category_id']);
$table->index('categorizable_type');
});
}
categories migration file is below
Schema::create('categories', function (Blueprint $table) {
$table->increments('tag_id');
$table->string('name');
$table->string('normalized');
$table->timestamps();
$table->index('normalized');
});
How can I built structure or Am I going to true way?
Best Regards
So I am trying to figure a solution to this but not sure exactly how to do this. I have a table that stores all the shows that happen. In a given show I can have multiple providers attend that show. A provider could also attend many shows as well. So how do I store this in the DB and do the eloquent relationship?
Show Schema
Schema::create('shows', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->integer('number')->unsigned();
$table->dateTime('airDate');
$table->string('podcastUrl')->nullable();
$table->timestamps();
});
Provider Schema
Schema::create('providers', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('shortName')->nullable();
$table->string('image')->nullable();
$table->string('social')->nullable();
$table->timestamps();
});
Would I store the provider_id in the shows schema?
Update 1
So I created a new migration for a pivot table
Schema::create('provider_show', function (Blueprint $table) {
$table->integer('provider_id')->unsigned()->index();
$table->foreign('provider_id')->references('id')->on('providers')->onDelete('cascade');
$table->integer('show_id')->unsigned()->index();
$table->foreign('show_id')->references('id')->on('shows')->onDelete('cascade');
$table->primary(['provider_id', 'show_id']);
});
Then in the show model I created the following
public function providers()
{
return $this->belongsToMany(Provider::class);
}
Now when I am saving a new show I added a multiselect to select the providers I want
$show = new Show;
$show->name = $request->name;
$show->number = $request->number;
$show->airDate = $request->airDate;
$show->podcastUrl = $request->podcastUrl;
$show->providers()->attach($request->providerList);
$show->save();
Session::flash('message', "Created Successfully!");
return back();
Then when I save I get the following error
SQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constraint failed: provider_show.show_id (SQL: insert into "provider_show" ("provider_id", "show_id") select 1 as "provider_id", as "show_id" union all select 2 as "provider_id", as "show_id")
Create a provider_show migration which will act as your pivot table.
This table would contain both provider_id and show_id which will provide the many-to-many relationship between those entities.
Then on your Provider model you can provide a shows() method which returns a BelongsToMany relationship.
// In your Provider model
public function shows()
{
return $this->belongsToMany('App\Show');
}
Note that Laravel by default looks for a pivot table name based alphabetically on the two relationships.
You can also add the inverse on your Show model by providing a providers() method that also returns a BelongsToMany relationship.
I want to get this query using query builder:
SELECT *,
( SELECT sum(vendor_quantity)
from inventory
WHERE product_id = products.id
) as qty from products
I'm stuck with this part
(SELECT sum(vendor_quantity) from inventory where product_id = products.id)
I can do it using raw query but I want to know if there is a way to do it in query builder.
My Table Schema for products:
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('product_type',50);
$table->string('product_name',255);
$table->string('internal_reference',255);
$table->string('barcode',255);
$table->decimal('sale_price', 10, 2);
$table->decimal('cost', 10, 2);
$table->decimal('weight', 10, 2);
$table->decimal('volume', 10, 2);
$table->integer('added_by')->unsigned();
$table->timestamps();
});
// Foreign Keys
Schema::table('products', function(Blueprint $table) {
$table->foreign('added_by')->references('id')->on('users');
});
Stocks Table:
Schema::create('stocks', function (Blueprint $table) {
$table->increments('id');
$table->integer('product_id')->unsigned();
$table->integer('vendor')->unsigned();
$table->string('vendor_product_code',255);
$table->string('vendor_product_name',255);
$table->integer('vendor_quantity');
$table->decimal('vendor_price', 10, 2);
$table->date('vendor_produce');
$table->date('vendor_expiry');
$table->integer('added_by')->unsigned();
$table->timestamps();
});
// Foreign Keys
Schema::table('stocks', function(Blueprint $table) {
$table->foreign('product_id')->references('id')->on('products');
$table->foreign('vendor')->references('id')->on('customers');
$table->foreign('added_by')->references('id')->on('users');
});
can you just add what exactly do you need as output? Like what do you plan to throw at your view so I can give you the eloquent setup. From the migration above it looks like you're missing some tables like "inventory".
In any way - you first need to setup eloquent relationships between your models. For the two above, something like this:
class Stock extends Model{
public function product(){
return $this->belongsTo(Product::class);
}
}
and
class Product extends Model{
public function stock(){
return $this->hasMany(Stock::class);
}
}
Now, that sum of yours has me confused a bit... since vendor_quantity is a column in your stocks table... Do you need to get all the products and the corresponding foreign key values from the stocks table and then sum all the values in the vendor_quantity? If that's the case do something like this:
$products = Products::with('stock')->get();
This will return the eloquent collection with all your products AND foreign key values from the stock table. Since you have the values from the related table you can just iterate through each of those an add it to a variable or just append it to the initial object for passing to your view. For example
$products = Product::with('stock')->get();
foreach ($products as $key => $product){
$vendorQuantitySum = $product->stock->sum('vendor_quantity');
$products[$key]->vendorQuantity = $vendorQuantitySum;
}
Now, when you pass $products to your view, you can easily get the sum in your view like so:
{{ $product->vendorQuantity }}
I just tested it on my Laravel install and it seems to work :)
Laravel normalizing relationship in DB.
So I've jobs table that contains job. And categories table that contains category.
job can have multiple categories.
Is there a laravely way of normalizing the relationship?
Schema::create('jobs', function($table)
{
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->string('slug');
$table->string('title');
$table->string('excerpt')->nullable();
$table->text('content');
$table->integer('delivery');
$table->integer('price');
$table->unique(array('user_id', 'slug'));
$table->timestamps();
});
Schema::create('categories', function(Blueprint $table)
{
// These columns are needed for Baum's Nested Set implementation to work.
// Column names may be changed, but they *must* all exist and be modified
// in the model.
// Take a look at the model scaffold comments for details.
// We add indexes on parent_id, lft, rgt columns by default.
$table->increments('id');
$table->integer('parent_id')->nullable()->index();
$table->integer('lft')->nullable()->index();
$table->integer('rgt')->nullable()->index();
$table->integer('depth')->nullable();
// Add additional columns here (f.ex: name, slug, path, etc.)
$table->string('name')->unique();
$table->string('slug')->unique();
$table->string('description')->nullable();
});
My first instinct is to create an intermediary table that holds relationship:
Schema::create('jobs_categories', function($table)
{
$table->increments('id');
$table->integer('job_id')->unsigned();
$table->integer('category_id')->unsigned();
$table->unique(array('job_id', 'category_id'));
});
But I'm not sure how to proceede, what would I do if I want to get categories along with all $jobs?
What do I do if I want to get $job category?
Is hasOne, hasMany a better suited for this?
What you're describing is a many-to-many relationship. And yes, a pivot table like jobs_categories is needed. Here's how you do it following Laravels naming convention and making use of relationships:
Pivot table
jobs_categories is fine but Laravel likes category_job (singular and alphabetical order) (This way you don't have to specify the table name in your relation)
Schema::create('category_job', function($table){
$table->increments('id');
$table->integer('job_id')->unsigned();
$table->integer('category_id')->unsigned();
$table->unique(array('job_id', 'category_id'));
// foreign key constraints are optional (but pretty useful, especially with cascade delete
$table->foreign('job_id')->references('id')->on('jobs')->onDelete('cascade');
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
});
Relationships
Job model
public function categories(){
return $this->belongsToMany('Category');
}
Category model
public function jobs(){
return $this->belongsToMany('Job');
}
Usage
Jobs with categories eager loaded
$jobs = Job::with('categories')->get();
Access categories of a job
$job = Job::find(1);
$categories = $job->categories;
Visit the Laravel docs for more information on Eloquent relationships
I have an application tha i want it to make bookings but i'am having trouble making my Eloquent query
I have two modals "Booking.php" and "Room.php" my bookings migrations table is as follows
Schema::create('bookings', function(Blueprint $table)
{
$table->increments('id');
$table->string('name');
$table->integer('phone');
$table->integer('time_in');
$table->integer('room_id');
$table->integer('time_out');
$table->string('days');
$table->string('type');
$table->integer('expiry_status'); /*expiry status 0->expired 1->not expired*/
$table->timestamps();
});
and my rooms migrations table is as follows
Schema::create('rooms', function(Blueprint $table)
{
$table->increments('id');
$table->integer('room_no');
$table->integer('price');
$table->timestamps();
});
in my view i have got inputs for satrt of reservation(time_in) and end of reservation(time_out) now if there is a reservation that does not end before or start after the reservation we want, the room is considered busy therefore i do not want to show that room show those rooms for my reservation dates.
My problem is I want to know the rooms available between my reservation dates,Can someone help me to write the eloquent to get the available rooms from the above table structures. I'm using mysql as the database engine. Thanks in advance.
I found this query to be useful but how to i implement it in the form of Eloquent model
SELECT r.id
FROM rooms r
WHERE r.room_id NOT IN (
SELECT b.room_id FROM bookings b
WHERE NOT (b.time_out < '2012-09-14T18:00'
OR
b.time_in > '2012-09-21T09:00'))
ORDER BY r.room_id;
You can create subselects and advanced where conditions in Laravel Eloquent.
This script worked for me. I tried to build it for your schema.
DB::table('rooms')
->whereNotIn('room_id', function($query)
{
$query->select('room_id')
->from(with(new Booking)->getTable())
->where(function($query)
{
$query->where('time_out', '<', '2012-09-14T18:00')
->orWhere('time_in', '>', '2012-09-21T09:00');
});
})
->orderBy('room_id')
->get();
https://gist.github.com/DengoPHP/d3e95441a7b9e27299b7