I have 4 tables that I'm trying to work with in Laravel and I can't figure out how to use eloquent to execute a particular query. I want to update all orders that belong to a user (through product_id) and that have null payout_id.
This raw sql statement works but I'm not sure how to use eloquent for this..perhaps sync?
UPDATE order_items i JOIN products p on (i.product_id = p.id) SET i.payout_id = null where p.user_id = 3
User Model
Product Model
FK: user_id
Order Model
FK: product_id
FK: payout_id
Payout Model
I would really appreciate any help!
First define a function orders in User Model
public function orders()
{
return $this->hasManyThrough('Orders', 'Product','user_id','product_id');
}
User::where('id','=',$userid)->with(array('orders'=>function($query){
$query->where('payout_id','=',0)->update(array('payout_id'=>$updatevalue));
}))->first();
You need to create a model for your tables i and p, see http://laravel.com/docs/eloquent for full information on model creation.
In the model for i you would then create a relationship to p:
public function p()
{
return $this->('p','id','product_id');
}
You can then run your query as follows:
$results = i::with('p')
->where('user_id', '=', 3)
->update(array('payout_id' => null));
Related
I have 4 table categories, initiatives, a pivot table for the "Many To Many" relationship category_initiative and initiativegroup table related with initiatives table with initiatives.initiativesgroup_id with one to many relation.
With pure sql I retrive the information I need with:
SELECT categories.id, categories.description, initiatives.id, initiatives.description, initiativegroups.group
FROM categories
LEFT JOIN category_initiative ON categories.id = category_initiative.category_id
LEFT JOIN initiatives ON category_initiative.initiative_id = initiatives.id
LEFT JOIN initiativegroups ON initiatives.initiativegroup_id = initiativegroups.id
WHERE categories.id = '40'
How can I use eloquent model to achieve same results?
Since you have such a specific query touching multiple tables, one possibility is to use query builder. That would preserve the precision of the query, retrieving only the data you specifically need. That would look something like this:
$categories = DB::table('categories')
->select([
'categories.id',
'categories.description',
'initiatives.id',
'initiatives.description',
'initiativegroups.group',
])
->leftJoin('category_initiative', 'categories.id', '=', 'category_initiative.category_id')
->leftJoin('initiatives', 'category_initiative.initiative_id', '=', 'initiatives.id')
->leftJoin('initiativegroups', 'initiatives.initiativegroup_id', '=', 'initiativegroups.id')
->where('categories.id', '=', 40)
->get();
In your models define the relationships:
Category.php model
public function initiatives()
{
return $this->belongsToMany('App\Initiative');
}
Initiative.php model (If has many categories change to belongs to many)
public function category()
{
return $this->belongsTo('App\Category');
}
Then maybe change your initiativegroup -> groups table, and then create a pivot table called group_initiative. Create model for group. Group.php and define the relationship:
public function initiatives()
{
return $this->belongsToMany('App\Initiative');
}
Then you can also add the following relationship definition to the Initiative.php model
public function group()
{
return $this->belongsTo('App\Group');
}
That should get you started.
for the record..
with my original relationship, but changing table name as alex suggest, in my controller:
$inits = Category::with('initiative.group')->find($id_cat);
simple and clean
I have found this: Get Specific Columns Using “With()” Function in Laravel Eloquent
but nothing from there did not help.
I have users table, columns: id , name , supplier_id. Table suppliers with columns: id, name.
When I call relation from Model or use eager constraints, relation is empty. When I comment(remove) constraint select(['id']) - results are present, but with all users fields.
$query = Supplier::with(['test_staff_id_only' => function ($query) {
//$query->where('id',8); // works only for testing https://laravel.com/docs/6.x/eloquent-relationships#constraining-eager-loads
// option 1
$query->select(['id']); // not working , no results in // "test_staff_id_only": []
// option 2
//$query->raw('select id from users'); // results with all fields from users table
}])->first();
return $query;
In Supplier model:
public function test_staff_id_only(){
return $this->hasMany(User::class,'supplier_id','id')
//option 3 - if enabled, no results in this relation
->select(['id']);// also tried: ->selectRaw('users.id as uid from users') and ->select('users.id')
}
How can I select only id from users?
in you relation remove select(['id'])
public function test_staff_id_only(){
return $this->hasMany(User::class,'supplier_id','id');
}
now in your code:
$query = Supplier::with(['test_staff_id_only:id,supplier_id'])->first();
There's a pretty simple answer actually. Define your relationship as:
public function users(){
return $this->hasMany(User::class, 'supplier_id', 'id');
}
Now, if you call Supplier::with('users')->get(), you'll get a list of all suppliers with their users, which is close, but a bit bloated. To limit the columns returned in the relationship, use the : modifier:
$suppliersWithUserIds = Supplier::with('users:id')->get();
Now, you will have a list of Supplier models, and each $supplier->users value will only contain the ID.
Assume this:
class List extends Model
{
public function items(){
return $this->hasMany(Items::class, 'c.class_id', 'class_id')
->rightjoin('items_classes as c', 'c.items_id', '=', 'items.id');
}
}
The problem is that Eloquent prepends items to foreign key field and the final query is:
SELECT * FROM items
RIGHT JOIN items_classes as c ON c.items_id = items.id
// here it is
WHERE items.c.class_id = 10
Even using DB::raw('c.class_id') didn't solve the problem.
If you notice the signature of hasMany relation method :
return $this->hasMany(Model::class, 'foreign_key', 'local_key');
Which means when Laravel will make the query, it will consider second argument foreign_key as a column of table defined in Model::class.
To simplify in your case :
return $this->hasMany(Items::class, 'c.class_id', 'class_id')->...
Leaving the rightjoin aside for a moment, Laravel is considering c.class_id as a foreign key of Item::class table which is indeed items table.
So the resultant query is :
SELECT * FROM items WHERE items.c.class_id = 10
Then when you add the right join, laravel just adds into the main query and makes it :
SELECT * FROM items
RIGHT JOIN items_classes as c ON c.items_id = items.id
WHERE items.c.class_id = 10
Laravel will not refer items_classes in the relation because you are relating List Model to Item::class and not ItemClass::class.
I am not sure about the data you need but see if you can use with like below :
class List extends Model
{
public function items(){
return $this->hasMany(Items::class, 'c.class_id', 'class_id');
}
}
List::with(['items', function($q){
return $q->->rightjoin('items_classes as c', 'c.items_id', '=', 'items.id');
}])->get();
Hope this gives you an idea how you can update your relationships to get desired query. If you add your table structure and data you want, I can update the answer with relationships for you.
I'm trying to select specific columns from tables that I have joined using Eloquent.
I have 3 models
- Transaction
- Channel
- Merchant
Transactions links to Channel. It has a hasOne relationship.
Channel links to Merchant. It also has a hasOne relationship.
public function channel() {
return $this->hasOne(Channel::class, 'uuid', 'entityId');
}
public function merchant() {
return $this->hasOne('App\Merchant', 'uuid', 'sender');
}
I'm using eager loading so have the following in the Transaction model:
protected $with = ['channel'];
And Channel has:
protected $with = ['merchant']:
This the query I'm trying to convert into Eloquent but I'm unsure how to select columns when they belong to related models. What I don't get is that if the relationships have been defined, why can't I select columns from the other models without having to reuse joins or the with clause?
SELECT SUM(t.amount) AS amount,
m.name
FROM transactionsV2 t JOIN
channels c
ON t.entityId = c.uuid JOIN
merchants m
ON c.sender = m.uuid
WHERE t.paymentType = 'DB' AND
t.status = 1 AND
t.processing_time >= '2019-01-01' AND
t.processing_time < '2019-01-21'
GROUP BY m.name;
You could do something like protected $with = ['merchant:id,name']; or maybe use raw expressions like selectRaw('SUM(t.amount) AS amount, m.name)
You can try something like this :
Transaction::sum('amount')
->whereStuf(...)
->with(['channel.merchant' => function($query){
$query->select('name')
->groupBy('name');
}])->get();
The channel.merchant allows you to get the nested relation.
I have 4 tables:
Account (id, name)
Type (id, account_id, name)
Category (id, type_id, name)
Money (id, category_id, date, amount)
And I defined the relations at model
But my problem is how to get money data with account id 2?
Account::find(2)-> type()-> category()->money
Is not working
Assuming you created your relationships, you can do it this way:
$account = Account::with('type.category.money')->find(2);
and to display money you can now use:
echo $account->type->category->money->amount;
In above echo I of course assume for each record you have data in all those tables. If not, you'll need to add extra checking to make sure you don't display property for null
You can also go about this from the other direction if you only need the final result of 'money' and have the inverse relationships setup on the models.
$money = Money::whereHas('category.type.account', function ($q) use ($id) {
$q->where('id', $id);
})->get();
// get() or first() depending whether these relationships return many
Laravel Docs - Eloquent Relationships - Querying Relationships - Querying Relationship Existence