How to combine multiple results while joining tables - php

I have a query which returns names of categories and its subcategories.
$subcategories = Subcategory::select('subcategories.name as subcatname', 'categories.name as catname')
->join('categories', 'subcategories.idCategory', '=', 'categories.id')
->get();
And now I get results like:
'Music' => 'Jazz',
'Music' => 'Rock',
'Music' => 'Pop',
'Movie' => 'Action'
How can I group it to have something like this:
'Music' => array('Jazz', 'Rock','Pop'),
'Movies' => array('Action')
Is it possible without making to much looping iterations and checking which subcategory belongs to which category?

You can use laravel collection
First you need to group by groupBy method, then map each group and merge every child array.
$result = collect($subcategories)
->groupBy('catname')
->map(function ($item) {
return array_merge($item->toArray());
})->all();

Related

Laravel eloquent query relationship with an added column using selectRaw

I started the query like this:
$students = StudRegProfile::with(['my_campus','work_experience' => function($query) {
$query->selectRaw('*, datediff(dateend, datestart) / 360 as years_of_experience');
}]);
Update:
My query is now like this:
$students = StudRegProfile::with(['my_campus','work_experience'])
->withCount([
'work_experience as years_of_experience' => function($query) {
$query->select(\DB::raw('SUM(datediff(dateend, datestart) / 360)'));
}
]);
Now I have years_of_experience as column in work_experience relationship. My output looks like this:
[
id => 1,
work_experience => [
id => 1,
years_of_experience => 2.4417,
]
]
But when I filter it like this:
$students->whereHas('work_experience', function($query) {
$query->whereRaw('years_of_experience >= 2');
});
It can't find my years_of_experience column.
Query Log:
Update:
My StudRegProfile hasMany work_experience. My work experience has datestart and endstart. I want to get the total difference in datestart and endstart so I can filter it as and input in my form

Join foreach laravel query

i have this
public function deals(){
$matchThese = [ 'suspended' => 0, 'status' => 1, 'approved' => 1 ];
$deals = ListsDeals::where( $matchThese )->orderBy( 'start_date' )->get();
$list = DB::table( 'lists' )
->join( 'list_has_deals', 'lists.id', '=', 'list_has_deals.list_id' )
->where( 'list_has_deals.deal_id', '=', 12)
->select( 'lists.id' )
->get();
$categories = DB::table( 'lists_categories' )
->join( 'list_has_categories', 'lists_categories.id', '=', 'list_has_categories.category_id' )
->where( 'list_has_categories.list_id', '=', $list[0]->id )
->select( 'lists_categories.title' )
->get();
return view( "deals" )
->with( "deals", $deals )
->with( "categories", $categories );
}
I want to obtain the value of title for the categories in lists, but first i need to obtain the deals for the lists in less words
I have
Deals - Lists - lists_has_deals
Categories - Lists - lists_has_deals
Both are belongsToMany, i want obtain in the deals the categories belonging to the list that is associated with the offer.
In my example that works fine but the 12 need to be a foreach of the $deals not be number static, thanks for the help.
Try using a has many through or intermediate pivot table on lists_has_deals. If I'm understanding your question, lists should have the necessary reference to both deals and categories.
https://laravel.com/docs/5.4/eloquent-relationships#has-many-through
https://laravel.com/docs/5.4/eloquent-relationships#many-to-many
specifically withPivot()

Add a new column with a value to the select query in Laravel

I would like to know how to create a default variable called "type" and set a value to "car" while doing a select join in Laravel.
Here is my code so far:
$items = DB::table('items')->orderBy('created_at', 'desc')
->join('items_categories', 'items.item_category_id', '=', 'items_categories.category_id')
->select(
'items.id as items___item_id',
'items.item_title as items___item_title',
'items_categories.id as items_categories___category_id',
'items_categories.title as items_categories___category_title',
)
->take(20);
This works nice. However, I need to get/add a custom key and value for each record of this select so I can use it later in the template to filter stuff further.
So, I need to add a key called type with a value of car so in the print_r I will see type => car for every record and I can use this in my code.
How to do that?
Can I put that somhow in the select?
Like:
->select(
'items.id as items___item_id',
'items.item_title as items___item_title',
'items_categories.id as items_categories___category_id',
'items_categories.title as items_categories___category_title',
//something like this?
'type' = 'car'
)
Because right now I am getting this:
Array
(
[0] => stdClass Object
(
[items___item_id] => 10
[items___item_user_id] => 2
[items___item_title] => A new blue truck
[items_categories___category_id] => 1
[items_categories___category_title] => Truck
)
[1] => stdClass Object
(
[items___item_id] => 11
[items___item_user_id] => 2
[items___item_title] => VW Tiguan
[items_categories___category_id] => 1
[items_categories___category_title] => SUV
)
And I want to get this:
Array
(
[0] => stdClass Object
(
[items___item_id] => 10
[items___item_user_id] => 2
[items___item_title] => A new blue truck
[items_categories___category_id] => 1
[items_categories___category_title] => Truck
[type] => car
)
[1] => stdClass Object
(
[items___item_id] => 11
[items___item_user_id] => 2
[items___item_title] => VW Tiguan
[items_categories___category_id] => 1
[items_categories___category_title] => SUV
[type] => car
)
If possible, not in the model file, but during the one query, because it's only one time when I need this modification to be done.
You can use this method:
$data = DB::table('items')
->Select('items.id as items___item_id',
'items.item_title as items___item_title');
# Add fake column you want by this command
$data = $data->addSelect(DB::raw("'fakeValue' as fakeColumn"));
$data = $data->orderBy('items.id')->get();
Enjoy it!
You will want to create a model for your items table and query it that way. Using eloquent, you can create columns on the fly by adding column names to the $appends property and then defining a model attribute.
php artisan make:model Item
Any model automatically looks for a table that is the plural of the model name (Item looks for 'items'). In the Item model, add the following lines
/**
* Append custom columns to the model
*
* #var array
*/
protected $appends = ['type'];
/**
* Define the type column to every Item object instance
*
* #return string
*/
public function getTypeAttribute()
{
return 'car';
}
Now update your query to use the model instead of DB::select. Make sure to use the model at the top of your controller
use App\Item;
....
$items = Item::orderBy('created_at', 'desc')
->join('items_categories', 'items.item_category_id', '=', 'items_categories.category_id')
->select(
'items.id as items___item_id',
'items.item_title as items___item_title',
'items_categories.id as items_categories___category_id',
'items_categories.title as items_categories___category_title',
)
->take(20)->get();
You need to add get() as the final method when using a Model for it to return a collection vs. DB::select.
Here is the solution for this problem, hope it helps somebody else in the future.
$items = DB::table('items')->orderBy('created_at', 'desc')
->join('items_categories', 'items.item_category_id', '=', 'items_categories.category_id')
->select(DB::raw('"car" AS type,
items.id as items___item_id,
items.item_title as items___item_title,
items_categories.id as items_categories___category_id,
items_categories.title as items_categories___category_title
')
)
->take(20);
I came across the same requirement, I know it is late but it might help someone in the future:
Here is my code how to a add a custom field in Laravel eloquent model
$searchResults = Blog::with('categories')
->where('title', 'like', "%{$keyword}%")
->orWhere('description', 'like', "%{$keyword}%")
->select(['*', DB::raw("'{$keyword}' as keyword")])
->get();
Thanks
i implement it sth like this sample
$first = Message::where('from_id', '=', Auth::user()->id)
->where('to_id', '=', $id)->get();
foreach ($first as $f)
$f->is_sent = true;
$second = Message::where('from_id', '=', $id)
->where('to_id', '=', Auth::user()->id)->get();
foreach ($second as $s)
$s->is_sent = false;
$chats = $first->merge($second)
->sortBy('created_at');
return $chats->toJson();
you can do it by for eachafter get() method

Laravel 5.1 database order by few columns

I want to sort result from database by few colums.
I trying like this:
Video::select('videoss.name as videoname', 'videos.*')->join('users', 'users.id', '=', 'videos.user_id')
->orderBy('videos.name', 'desc')
->orderBy('videos.views', 'desc')
->paginate(15);
but it is sorted only by name. How add sorting by views after sort by name.
Have you tried in an array as explained in the comments here like this:
$user->orders = array(array('column' => 'name', 'direction' => 'desc'), array('column' => 'email', 'direction' => 'asc'));

Codeigniter Join messing up 'id' field

I have a codeigniter query to get a list of questions from my database. I'm using some joins to get the category name and the answer type. Its working good to output everything, but when i try and output the id of the row from the "questions" table, it displays as "2" which is the answer_type_id.
Maybe I'm doing this wrong, i'm fairly new to joins. Any help is appreciated:
function get_questions($category_id) {
$this->db->select('*');
$this->db->from('questions');
$this->db->where('category_id', $category_id);
$this->db->join('categories', 'questions.category_id = categories.id');
$this->db->join('answer_type', 'questions.answer_type_id = answer_type.id');
$this->db->order_by('priority', 'desc');
$query = $this->db->get();
$data = array();
foreach ($query->result() as $row) {
$data[] = array(
'id' => $row->id,
'category' => $row->category,
'type' => $row->type,
'question' => $row->question,
'answer' => $row->answer_type,
'priority' => $row->priority,
);
}
return $data;
}
Update===============
I have added "left" for my join type but the problem persists. The question id's should be 2 and 3. But when i print my array returned, they are both 2 (which is the answer_type_id).
Here is the updated code (only left join changed)...
function get_questions($category_id) {
$this->db->select('*');
$this->db->from('questions');
$this->db->where('category_id', $category_id);
$this->db->join('categories', 'questions.category_id = categories.id', 'left');
$this->db->join('answer_type', 'questions.answer_type_id = answer_type.id', 'left');
$this->db->order_by('priority', 'desc');
$query = $this->db->get();
$data = array();
foreach ($query->result() as $row) {
$data[] = array(
'id' => $row->id,
'category' => $row->category,
'type' => $row->type,
'question' => $row->question,
'answer' => $row->answer_type,
'priority' => $row->priority,
);
}
return $data;
}
And here is the output it returns:
Array (
[0] => Array (
[id] => 2
[category] => Herbs
[type] => 2
[question] => What Type of Vehicle do You own?
[answer] => Drop down list [priority] => 0
)
[1] => Array (
[id] => 2
[category] => Herbs
[type] => 3
[question] => What is Your Favorite Herb
[answer] => Drop down list [priority] => 0
)
)
The reason you are not getting the proper ids is you are selecting *.
Use aliases so that give them separate names and you will be access them
as you want like this.
function get_questions($category_id) {
$this->db->select('questions.*');
$this->db->select('answer_type.answer_type_id');
$this->db->select('answer_type.other_column');
$this->db->from('questions');
$this->db->where('category_id', $category_id);
$this->db->join('categories', 'questions.category_id = categories.id', 'left');
$this->db->join('answer_type', 'questions.answer_type_id = answer_type.id', 'left');
$this->db->order_by('priority', 'desc');
return $this->db->get()->result_array();
}
Also Codeigniter database class provide a method call result_array()
Which is already alternate of the loop you are using. So use it instead of
extra loop code.
Just change it to this:
'id' => $row->category_id
The problem is that the id column is ambiguous. In cases where your selecting columns across tables with columns that have the same name, you can also use the AS keyword to rename a column.
For example:
$this->db->select("questions.*, categories.id AS cat_id, answer_type.id AS ans_id");
By chance are you (maybe) only getting one row as a result, where all the ids match?
You should specify your join type, or be more specific in your query, so that you keep the question.id value.
For this question, you could specify the join as a left join, to keep all the data from questions table and tack on from categories and answer_types where its found.
see CodeIgniter ActiveRecord docs
The questions id needs to be defined as its own name. To pull ALL the data from the other tables, follow up with asterisks for the other tables, like so...
function get_questions($category_id) {
$this->db->select('questions.id as questions_id, questions.*, categories.*, answer_type.*');
$this->db->from('questions');
$this->db->where('category_id', $category_id);
$this->db->join('categories', 'questions.category_id = categories.id', 'left');
$this->db->join('answer_type', 'questions.answer_type_id = answer_type.id', 'left');
$this->db->order_by('priority', 'desc');
$query = $this->db->get();
$data = array();
foreach ($query->result() as $row) {
$data[] = array(
'id' => $row->questions_id,
'category' => $row->category,
'type' => $row->type,
'question' => $row->question,
'answer' => $row->answer_type,
'priority' => $row->priority,
);
}
return $data;
}
Use alias for your id columns like the above example.
...
$this->db->select("questions.*, categories.id AS cat_id, answer_type.id AS ans_id");
...
...
Now you get your data because only have one id column.
Here you have an article: http://chrissilich.com/blog/codeigniter-active-record-aliasing-column-names-to-prevent-overwriting-especially-columns-named-id/

Categories