Merge Model and its Relationship with result like join query in laravel - laravel

I'm new at Laravel and Programming at that. I have a problem joining model with its relationship, here is what my model:
class MainClass extends Model
{
public function first()
{
return $this->hasMany(First::class);
}
public function second()
{
return $this->hasMany(Second::class);
}
public function third()
{
return $this->hasMany(Third::class);
}
}
When i try to get MainClass records then load it's relationship like:
$main = Main::where('status', 'ready')->get()
$main->load(['first','second'])
Here's what i got:
[{
"id":"1",
"name":"First Person",
"status": "ready",
"first":[
{"main_id": "1", "prop":"One"},
{"main_id":"1", "prop":"Two"}],
"second":[
{"main_id": "1", "other":"Yes"},
{"main_id":"1", "other":"Two"},
{"main_id":"1", "other":"Three"}]
},{
"id":"5",
"name":"Fifth Person",
"status": "ready",
"first":[
{"main_id": "5", "prop":"Five"},
{"main_id":"5", "prop":"Six"}],
"second":[
{"main_id": "5", "other":"Laptop"},
{"main_id":"5", "other":"Pc"}]
}]
How can i merge that relationship so the result will be like join query,
this is what i want:
[{
"id":"1",
"name":"First Person",
"status": "ready",
"prop":"One",
"other:"Yes"
},{
"id":"1",
"name":"First Person",
"status": "ready",
"prop":"Two",
"other":"Two"
}]
I know there is a way to combine collection with merge or push in laravel, but i can't seem to get it right.
As of why not using join query, because i want to load relationship dynamically, so relation is not always loaded, but sometime they do. While join query, i have to write it manually (as far as i know) :-)
Maybe someone can point me somewhere, or maybe there is a package for something like this?
Thanks in advance

Use eager loading, fetching the collection, then run groupBy, then the each, then the map function to return the results formatted as your wish.
Why not just simply run the joins

You can do it with join;
$main = Main::query()->select(['main.id', 'main.name', 'main.status', 'f.prop', 's.other', 't.blabla'])
->leftJoin('first as f', 'f.main_id', 'main.id')
->leftJoin('second as s', 's.main_id', 'main.id')
->leftJoin('third as t', 't.main_id', 'main.id')
->where('main.status', 'ready')
->get();

Related

Why laravel returns an empty array for a has many relationship?

I am using jenssegers/laravel-mongodb and i have schema is like below
Ticket Collection :
{
"_id": ObjectId("5f32d9bb486e94459b6531c3"),
"subject": "\"URGENT\" Non-Compliance In (Eastern Region)",
"content": "abc",
"user_team": "5f044199e40dfe4847056785",
"team_ids": [
"5f3012bbb7c2bc422e4da5a2"
],
"organization_id": "5f74359c7dcc8f6fbb2b47e2"
}
Team Collection :
{
"_id":ObjectId("5f3012bbb7c2bc422e4da5a2"),
"name": "Medical Maintenance",
"createTickets": true
}
Relationship in Ticket Model :
public function teams()
{
return $this->HasMany('App\Team', 'team_ids');
}
Relationship in Team Model :
public function ticket()
{
return $this->belongsTo('App\Ticket');
}
I am facing an issue to get data for teams relationship. It return an emtpry array.
Laravel version is 6.2
jenssegers/mongodb version is 3.6
Your approach to the foreign key is wrong, when in the context of hasMany. Instead a single column called team_id should be on the ticket and then you can do the following.
public function teams()
{
return $this->HasMany('App\Team', 'team_id');
}
Which would work if your ticket looks like so.
{
"_id": ObjectId("5f32d9bb486e94459b6531c3"),
"subject": "\"URGENT\" Non-Compliance In (Eastern Region)",
"content": "abc",
"user_team": "5f044199e40dfe4847056785",
"team_id":"5f3012bbb7c2bc422e4da5a2"
"organization_id": "5f74359c7dcc8f6fbb2b47e2"
}
Instead it looks like you are actually doing a many to many, because one team can have many tickets and reverse. This can be defined like so, this will probably add the data to both models, but I'm not an expert on Mongodb in Laravel.
public function teams()
{
return $this->belongsToMany(
Team::class, null, 'ticket_ids', 'team_ids'
);
}
You can find all of this in the documentation.
You could specify foreign and local keys.
Example:
public function teams()
{
$this->hasMany('App\Team', 'team_ids', '_id')
}

How to query without using Eloquent?

I have these few tables:
issues
1. id
2. name
tags
1. id
2. name
issue_tag
1. issue_id
2. tag_id
images
1. id
2. url
3. issue_id
The relationship of these tables is stated below:
Issue hasMany Images, Images belongsTo Issue
Issues belongsToMany Tags, Tags belongsToMany Issues
How can I retrieve all the records by NOT USING ELOQUENT, just by using the QUERY BUILDER. I would like to retrieve the data in the format like:
[
{
id: issue_id,
name: issue_name,
tags: [
{
id: tag_id_1,
name: tag_name_1
},
{
id: tag_id_2,
name: tag_name_2
}
]
},
{
...
},
...
]
Please someone help me because I could not solve this problem for a long time, I can only solve it by using Eloquent. But using Eloquent is not a solution for me.
You can use join query. For Details follow this link demo
Or
Use DB:: statement ('your raw query here'). Hope this helps.
Use can Laravel DB::select(); function
With the use of select, we can pass Raw SQL query into select
$innerData = [];
$issueAll = DB::select('select i.id,i.name,i2.url as image,t.id as tag_id,
t.name as tag_name,it.issue_id from issues as i
inner join issue_tag as it on it.issue_id=i.id
inner join tags as t on it.tag_id = t.id
inner join images as i2 on i.id = i2.issue_id
');
foreach ($issueAll as $issue) {
$innerData[$issue->id]["id"] = $issue->id;
$innerData[$issue->id]["name"] = $issue->name;
if (isset($innerData[$issue->id]['tags'][$issue->issue_id])) {
array_push($innerData[$issue->id]['tags'], ['id'=>$issue->tag_id, 'name'=>$issue->tag_name]);
} else {
$innerData[$issue->id]['tags'][$issue->issue_id] = ['id'=>$issue->tag_id, 'name'=>$issue->tag_name];
}
}
return $innerData;
The response you get
{
"1":{
"id":1,
"name":"issue1",
"tags":{
"1":{
"id":1,
"name":"tag1"
},
"2":{
"id":1,
"name":"tag1"
}
}
},
"2":{
"id":2,
"name":"issue2",
"tags":{
"2":{
"id":1,
"name":"tag1"
}
}
}
}
Hope it helps.
In laravel if you don't want to use eloquent then you can use with DB::statement('your query') and don't forget to use USE DB; at the top of the file

Laravel Eloquent getting value from previous relation/pivot

I have a bunch of results coming from eager loading through many to many relations. I need to filter one thing, I have this output :
"id_stats":32,
"n_stats":"Mastery",
"image_stats":null,
"pivot":{
"id_equipement":11,
"id_stats":32,
"weight":"235",
"rand-elem":"3"
},
"elements":[
{
"id_elements":2,
"n_elements":"Feu",
"pivot":{
"id_stats":32,
"id_elements":2,
"id_equipement":15
}
},
{
"id_elements":3,
"n_elements":"Eau",
"pivot":{
"id_stats":32,
"id_elements":3,
"id_equipement":13
}
}
]
I must filter the equipement on pivot(parent).id_equipement = elements.id_equipement otherwise I will have the result of the whole table. I can either filter my result like this. I already tried to add an inner join in my belongsToMany relation but it didn't help!
Here is parts of my code:
EncyclopedieModel.php
public function stats(){
return $this->belongsToMany(StatsModel::class, 'equipement_stats', 'id_equipement','id_stats')
->withPivot('weight')->withPivot('random');
}
StatsModel.php
public function elements(){
return $this->belongsToMany(ElementModel::class, 'stuff_equipement_stats_elements', 'id_stats', 'id_elements')
->withPivot('id_equipement');
}
Thanks!

where() and sort() not working for populated records in sails

I created a Sails application with two models Person and Department.
They are having a one-to-one relationship.Sails-mysql is the adapter using.When I am trying to populate department details along with Person using where() or sort() criteria the resulting records are not sorted or where() is not applied.
Person.js
attributes: {
firstname:{
alpha:true,
required:true
},
lastname:{
alpha:true,
required:true
},
age:{
numeric:true,
required:true
},
department:{
model:'Department'
}
}
Department.js
attributes: {
DepartmentName:{
required:true,
alpha:true
},
Description:{
required:true,
alpha:true
},
//relation
person:{
model:'Person'
}
}
PersonController.js
Person.find().populate('department').where({DepartmentName:{"startsWith":"hr"}}).sort('Description desc').exec(console.log);
is not working.
I tried where() and sort() in all the possible way like
var sort='DepartmentName desc';
and pass that variable in the populate() like one below:
Person.find().populate('department',sort).exec(console.log);
but that is also not working.In the same way I tried for where() also that is also a failure.
Help me in this.
For me this is working ;)
Person.find().populate('department', {
where: {
DepartmentName: {
'startsWith': 'hr'
}
},
sort: 'DepartmentName desc'}
).exec(......);
For more information check here: http://sailsjs.org/documentation/reference/waterline-orm/queries/populate
under section Populating a collection association

Laravel: how to parse string to json

I've created this code from laravel:
public function findConfig($id)
{
$config = DB::table('configuration')
->join('model', 'model.configuration_id','=', 'configuration.id')
->select('configuration.id','configuration.description', 'model.name','configuration.price')
->where('configuration.id','=', $id)
->get();
$encode = json_encode($config, JSON_UNESCAPED_SLASHES);
$response = Response::make($encode, 200);
$response->header('Content-Type', 'application/json');
return $response;
}
then the return is somehow like this
[{
"id": "1",
"description": "{\"item\":[{'colours\":[\"red\",\"blue\",\"green\"]},{\"motors\":[ {\"name\":\"450W/48V\",\"price\":\"2,000\"},{\"name\":\"550W/48V\", \"price\":\"3,000\" }] } ]}",
"name": "k5-A",
"price": "300000"
},
{
"id": "1",
"description": "{\"item\":[{'colours\":[\"red\",\"blue\",\"green\"]},{\"motors\":[ {\"name\":\"450W/48V\",\"price\":\"2,000\"},{\"name\":\"550W/48V\", \"price\":\"3,000\" }] } ]}",
"name": "r-A",
"price": "300000"
}
]
How can I remove the slashes and instead of string as return type, it should be in JSON?
As lukasgeiter said, generally it isn't a good idea to store json in a db. It may get difficult to filter by that field.
If you decide to do so, and need to get the decoded data, you can use an accessor in the model. I don't know if it is the best practice. If the description is saved in the db as a json you can do this:
For the "configuration" table you may have a "Configuration" model (The official Laravel website recommends to name the table in plural, and the model in it's singular, like: table -> configurations and the model configuration). In that file you can add this:
public function getDescriptionAttribute($value)
{
return json_decode($value, true);
}
Now, the description field is returned as an array.
You can see more about accessors and mutators here: http://laravel.com/docs/4.2/eloquent#accessors-and-mutators

Resources