how can i merge laravel relationship results in to one object?
MyController.php
public function getUser($id) {
return TournamentUser::where('customer_id','=', $id)->with('user')->get();
}
MyModel.php
public function user() {
return $this->hasOne('App\Models\Customer','customer_id', 'customer_id');
}
returning result :
[{
"id":1,
"tournament_id":3,
"customer_id":2016827550,
"point":0,
"user":{
"id":1,
"customer_id":2016827550,
"nickname":"OMahoooo"
}
}]
as expected query returns user section as array but i expect result like this :
[{
"id":1,
"tournament_id":3,
"customer_id":2016827550,
"point":0,
"nickname":"OMahoooo"
}]
only get nickname section without user array. I hope you understand me.
Sorry for my english , have a nice day
You can load the data and remap it manually using map() method. I've just tested this code and it works perfectly with hasOne() relationship:
$users = TournamentUser::where('customer_id', $id)->with('user')->get();
$users->map(function ($i) {
$i->nickname = $i->user->nickname; // Set related nickname.
unset($i->user); // Delete user data from the collection.
return $i;
});
Alternatively, you could use an accessor, but in this case, you'll meet the N+1 problem.
Related
I'm learning Laravel and need to get a list of nested relationships. My foreign keys seem to be set up correctly.
products->servers->configs
Product Controller
$products = Product::with('servers')->get();
Product Model
public function servers()
{
return $this->hasManyThrough(Config::class, Server::class);
}
I'm only getting a list of servers that are the configs. Eg
products:{
id:1,
servers:[
ram:16gb //this is the config not the server
]
}
How can I get the list of configs inside the servers inside the products? Eg
products:{
id:1,
server:{
id:1,
name:'big server',
config:{
ram:16gb
}
}
}
In Product Modal Use hasMany Method
public function servers()
{
return $this->hasMany(Server::class);
}
In Server Modal Use hasMany(for many rows get) or hasOne(for single row get) method
public function configs()
{
return $this->hasMany(Config::class);
}
public function config()
{
return $this->hasOne(Config::class);
}
Now In ProuctController see how to get nested relationship data
$products = Product::with('servers.configs')->get();
I'm having trouble retrieving data through relationships.
My database structure (simplified):
orders:
id
user_id
product_id
order_items:
order_id
product_id
I need to get using relationships, all orders along with the items in the array.
Order model:
public function items()
{
return $this->hasMany(OrderItem::class, 'order_id', 'id');
}
Test controller:
public function test()
{
return Order::with('items')->get();
}
Result I got when accessing test():
[
{
"id": "d7baaae9-b925-4ff0-8bba-13e8e88d429b",
"user_id": "fa2a5f73-379d-4ab7-9bc5-81cdbd47f3b0",
"subtotal": "0.00",
"discount": "0.00",
"coupon_code": "0",
"total": "0.00",
"paid": false,
"refunded": false,
"created_at": "2022-07-26T16:41:50.000000Z",
"updated_at": "2022-07-26T17:51:45.000000Z",
"items": [
]
}
]
The "items" array does not exist in the orders table, it is coming through the relationship, but it comes empty. There is a record in the database relating orders with order_items, the OrderItem model is correctly accessing the database when I test. I don't know what the problem could be.
[EDIT_01]: I just found out that the problem is in the id I'm using, I'm using type Uuid (Ramsey\Uuid\Uuid\Uuid::uuid4()) for the keys of my tables, somehow it's not working, but when I testo with conventional ID works. Help-me.
I have the same issue, my fix is I add
protected $keyType = 'string';
to the table which has string id (uuid). Hope it can help
hope you found a solution, if not testing out your code sample here, and everything works fine for me,
public function items()
{
return $this->hasMany(OrderItem::class);
}
use this instead, should give you a better result
Try removing the third parameter and just use this:
return $this->hasMany(OrderItem::class, 'order_id');
This should work given your Database setup example, make sure you actually have items in your database that belong to that order you are debugging as well.
Basically, I have three tables which are users, position, user_position and I want to get all users with their respective positions
Note that a single user can have multiple positions
The `user_position` table consists of:
- user_id
- position_id
To illustrate... it goes something like this:
users-->user_position<--position
What I got so far is this:
User Model
public function user_positions() {
return $this->hasMany('App\Models\UserPosition', 'user_id', 'id');
}
UserPosition Model
public function positions() {
return $this->hasMany('App\Models\Position', 'position_id', 'id');
}
UserController
public function getallusers() {
$data = User::with('user_positions')->get();
return response()->json($data);
}
So far it gives me the correct result set.
For example:
[{id:1,
name:'John',
user_positions:
[{id:1,
user_id:1,
position_id: 5
},
{id:2,
user_id:1,
position_id: 9
}
]
}]
However, it is incomplete, I also wanted the positions array inside the user_positions array but I don't know or I got lost on how to associate/merge/attach (i dont know the right term) the positions function to my User Model.
What you are looking for is a BelongsToMany relation.
You could add the following relation to your User model.
public function positions()
{
return $this->belongsToMany(Position::class);
}
You could eager load them with:
User::with('positions')->get();
Result:
[{
...
"positions": [{ ...The data of the position... }]
}]
When you want to m:m relation, it's advised to use BelongsToMany, there is no need for an intermediate model for the "pivoted" table.
If you have non-eloquent standard naming conventions. Then you have to specify the table name in the 2nd parameter as followed:
return $this->belongsToMany('App\Models\Positions', 'tbl_positions_assigned');
In the 3rd and 4th parameter you specify the foreign key names.
I'd like to refer to you to the documentation Eloquent-relationships as it's very thoroughly explained over there.
One very strong thing you can do with belongsToMany is to append extra columns in the pivot table. Those are also easily obtained from the pivot table. This is useful if you wish to store extra data values specific to the model.
return $this->belongsToMany('App\Models\Positions')->wherePivot('active', 1);
With above example you could exclude certain values, that are not active in this example, when you retrieve the results from the query.
I have two tables:
main_presentations
so here i have "id" and "isEnabled";
child_presentations
And here i have "id" , "isEnabled" and "idParent";
I want to select in one object this is my code:
public function MainSlider(MainPresentation $MainPresentations, ChildPresentation $ChildPresentations)
{
$MainPresentations = MainPresentation::where('isEnabled', true)->get();
foreach ($MainPresentations as $MainPresentation) {
$AnArray[] = ChildPresentation::where([
['idParent', $MainPresentation['id']],
['isEnabled', true]
])->get();
}
return $AnArray;
}
but this is the result:
enter image description here
What you are doing is executing a query per result, which can be ineffective when it starts getting bigger.
You can:
Use querybuilder
As it follows, you just build a query starting on ChildPresentation, set a relation to MainPresentation table by id and get the collection
public function MainSlider()
{
$childPresentations = ChildPresentation::join('main_presentations','main_presentations.id','child_presentations.idParent')
->where('child_presentations.isEnabled', true)->where('main_presentations.isEnabled', true)->get();
return $childPresentations;
}
If you want all the MainPresentations with their respective ChildPresentations, only the enables ones.
You can take advantage of Laravel relationships and eager loading.
https://laravel.com/docs/5.6/eloquent-relationships
First, set the relationships in your MainPresentation model
In MainPresentation.php
public function childPresentation {
return $this->hasMany('App\ChildPresentation', 'idParent', 'id');
}
Your MainSlider function would be:
(Btw, no idea why you're receiving two arguments if you're overriding them but doesn't matter)
public function MainSlider() {
$mainPresentations = MainPresentation::with(['childPresentations' => function ($advancedWith) {
child_presentation.isEnabled is true
$advancedWith->where('isEnabled', true);
}])
->where('isEnabled', true)->get()->toArray();
return $mainPresentations;
}
This will return an array of MainPresentations that contain an array of child_presentations, with all their childs.
This translates to two queries:
Select * from main_presentations where isEnabled = true;
Select * from child_presentations where isEnabled= true and id in (in the first query);
Laravel then does background work to create the structure you desire when you write ->toArray()
Note: If you have a $visible array in your MainPresentation model, be sure to add: 'childPresentation' to it, otherwise the toArray will not agregage the childs to the parent.
Second note: I advise following some standards whenever you're writing code, usually functions are named camelCase and variables are camelCase.
I'm having the following problem, I'm using scope in Laravel and I have the following relationship:
Enquiry
pickup_address
dropoff_address
Notes
This is referenced in the model:
public function pickup_address() {
return $this->belongsTo('App\Address', 'pickup_address', 'id');
}
I want to return the enquiry, as well as postcode which is stored in the Address table. I just want this column from this table and I have done the following:
return $query->with(['pickup_address' => function ($query) {
$query->select('postcode');
}])->get();
This gives the following (json):
{
"id":1,
"pickup_address":null
"notes":"hello world",
"created_at":"2017-06-08 09:56:52",
"updated_at":"2017-06-08 09:56:52"
}
This is not giving the postcode and just gives the pickup_address as null. However, removing the $query->select('postcode') gives:
{
"id":1,
"pickup_address": {
"id":140,
"house_number":null,
"address_1":"Address 1",
"address_2":null,
"postcode":"POSTCODE",
"city":"CITY",
"county":"C0UNTY",
"created_at":"2017-06-08 09:56:23",
"updated_at":"2017-06 0}",
"notes":"Hello world","
"created_at":"2017-06-08 09:56:52",
"updated_at":"2017-06-08 09:56:52"
}
However, I'm using Vue and using a table, so I just need the particular field to be returned that matches the column, rather than the entire object being returned.
Can anyone suggest a solution, please? I have followed some examples online and they suggest the $query->select('postcode')