Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

ramniksingh's avatar

Using Pluck to return columns from many to many tables with eloquent

Hi Everyone, I am trying to extract two columns with pluck() from many to many linked table.

'Materials' are linked with 'Sections' with many to many relation.

This works - returns all id's

public function getMaterialBySection($section){
        $filteredMaterials = Section::with('materials')->where('id', $section)->get()->pluck('materials.*.id');
        return json_encode($filteredMaterials); 
    }

This works - returns all names

public function getMaterialBySection($section){
        $filteredMaterials = Section::with('materials')->where('id', $section)->get()->pluck('materials.*.name');
        return json_encode($filteredMaterials); 
    }

But this doesn't works

public function getMaterialBySection($section){
        $filteredMaterials = Section::with('materials')->where('id', $section)->get()->pluck('materials.*.id', 'materials.*.name');
        return json_encode($filteredMaterials); 
    }

Why it is not returning both columns? Am I doing something wrong!

0 likes
14 replies
gitwithravish's avatar

Ramnik, pluck() retrieves all of the values for a given key. If you pass 2 values in the pluck(), it will return key => value pairs. So in your example you can retrive both columns like this

public function getMaterialBySection($section){

        $filteredMaterials = Section::with('materials')
              ->where('id', $section)
              ->get()
              ->pluck('materials.*.name', 'materials.*.id');

        return json_encode($filteredMaterials); 
}

$data = json_decode(getMaterialBySection($section));

foreach($data as $id => $name){

} 
ramniksingh's avatar

Thanks @gitwithravish But my question is the pluck method not returning data.

pluck('materials.*.id', 'materials.*.name')

gitwithravish's avatar

@ramniksingh

How about something simple like this,

public function getMaterialBySection($section){

        $filteredMaterials = Section::with([
		'materials' => function($query){
		    $query->select('id','name');
                 }])
              ->where('id', $section)
              ->first();

	return json_decode($filteredMaterials->materials ?? []);
}

ramniksingh's avatar

Thanks @gitwithravish . It worked.

ublic function getMaterialBySection($section) {
        $filteredMaterials = Section::with([
            'materials' => function($query){
                $query->select('materials.id','name');
                     }])
                  ->where('id', $section)
                  ->first();
        
        return json_encode($filteredMaterials->materials);
    }  

Can we further narrow down list to only id & name fields so that it can be fetched in my ajax data as key=>value pair?

gitwithravish's avatar

@ramniksingh

Well you can access it with javascript like this.

for(let material of response.data){
	console.log(material.id);
	console.log(material.name);
}

But if you want to go with key value pairs, then do this,

public function getMaterialBySection($section){

        $filteredMaterials = Section::with([
		'materials' => function($query){
		    $query->select('id','name');
                 }])
              ->where('id', $section)
              ->firstOrFail();

	return json_decode($filteredMaterials->materials ->pluck('name','id'));
}
ramniksingh's avatar
public function getMaterialBySection($section){

        $filteredMaterials = Section::with([
		'materials' => function($query){
		    $query->select('id','name');
                 }])
              ->where('id', $section)
              ->first();

	return json_decode($filteredMaterials->materials ?? []);
}

This returns error

same id exists in both tables .

gitwithravish's avatar

public function getMaterialBySection($section){

    $filteredMaterials = Section::with([
	'materials' => function($query){
	    $query->select('id','name');
             }])
          ->where('sections.id', $section)
          ->first();

return json_decode($filteredMaterials->materials ?? []);

}

ramniksingh's avatar
public function getMaterialBySection($section){
        $filteredMaterials = Section::with('materials')->where('id', $section)->get()->pluck('materials');
        return $filteredMaterials; 
    }

Above code works but I need a way to extract just key value pairs from selected columns.

My java script is like this :

jQuery('select[name="section_id"]').on('change',function(){
               var section = jQuery(this).val();
               if(section)
               {
                  jQuery.ajax({
                     url : 'filtermaterial/getmaterial/' +section,
                     type : "GET",
                     dataType : "json",
                     success:function(data)
                     {
                        console.log(data);
                        jQuery('select[name="material_id"]').empty();
                        jQuery.each(data, function(key,value){
                           $('select[name="material_id"]').append('<option value="'+ key +'">'+ value +'</option>');
                        });
                     }
                  });
               }
               else
               {
                  $('select[name="material_id"]').empty();
               }
            });
gitwithravish's avatar

@ramniksingh I would keep it simple like this :)

// you can pass section object or just section id in the arguments
public function getMaterialBySection($id){

    return Material::where('section_id',$id)
                   ->get()
                   ->pluck('name','id')
                   ->toJson;
}	      
ramniksingh's avatar

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'section_id' in 'where clause' (SQL: select * from materials where section_id = 1)

gitwithravish's avatar

well i just assumed that the foreign key for section in your materials table would be section_id. You change it to whatever it is

ramniksingh's avatar

there is no column named section_id in materials. material & section models are connected in many to many relation through a pivot table named 'material_section' .

gitwithravish's avatar
Level 16

oh damn i forgot. Sorry. Then you can go with the earlier solution.

php

$filteredMaterials = Section::with([
	'materials' => function($query){
	    $query->select('id','name');
             }])
          ->where('sections.id', $section)
          ->first();

return json_decode($filteredMaterials->materials ?? []);

js

jQuery('select[name="section_id"]').on('change',function(){
               var section = jQuery(this).val();
               if(section)
               {
                  jQuery.ajax({
                     url : 'filtermaterial/getmaterial/' +section,
                     type : "GET",
                     dataType : "json",
                     success:function(data)
                     {
                        console.log(data);
                        jQuery('select[name="material_id"]').empty();
                        jQuery.each(data, function(index,material){
                           $('select[name="material_id"]').append('<option value="'+ material.id +'">'+ material.value +'</option>');
                        });
                     }
                  });
               }
               else
               {
                  $('select[name="material_id"]').empty();
               }
            });
1 like

Please or to participate in this conversation.