Laravel Eloquent get all in single key value pair

Viewed 10029

I have two tables posts and post_metas with the schema as below:

POSTS
+------------+------------------+
| Field      | Type             |
+------------+------------------+
| id         | int(10) unsigned |
| title      | varchar(255)     |
| content    | longtext         |


POST_METAS
+------------+------------------+
| Field      | Type             |
+------------+------------------+
| id         | int(10) unsigned |
| post_id    | int(10) unsigned |
| key        | varchar(255)     |
| value      | longtext         |

using a simple one to many relationship, i get this output

[
  {
    "id": 1,
    "title": "Dibbert LLC",
    "content": null,
    "post_metas": [
      {
        "key": "code",
        "value": "YSRSLBZ7"
      },
      {
        "key": "agent_id",
        "value": "32"
      }
    ]
  }
]

I am wondering if it is possible to have the post metas as an object not an array, like this instead:

[
  {
    "id": 1,
    "title": "Dibbert LLC",
    "content": null,
    "post_metas": {
        "code": "YSRSLBZ7",
        "agent_id": "32"
      }
  }
]
2 Answers

You can't change how Eloquent returns relationship collections, nor should you want to, but you can certainly manipulate the collection in your response:

$model->post_metas->pluck('value', 'key');

Read up on all the available collection methods.

Laravel by default return an instance of the Collection class. This is also applied when querying relationship elements.

Now, if you want to customize the fields to be returned (hide, transform or add something, for example), you could use API Resources. This will let you easily transform your responses.

Check this other answer to help you with API Resources.


Update

To implement API Resources to your needs we'll need to:

  1. Define the PostResource and PostMetaResource classes.
  2. Customize them
  3. Use them in the controller to return the desired data to the view/API

Defining API Resources classes

php artisan make:resource PostMetaResource
php artisan make:resource PostResource

Customization

App/Http/Resources/PostMetaResource.php

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\Resource;

class PostMetaResource extends Resource
{
    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request
     * @return array
     */
    public function toArray($request)
    {
        return [
            'key' => $this->key,
            'value' => $this->value,
        ];
    }
}

App/Http/Resources/PostResource.php

class PostResource extends Resource
{

    use PostMetaResource;

    /**
     * Transform the resource into an array.
     *
     * @param  \Illuminate\Http\Request
     * @return array
     */
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            // the rest of your fields..

            // here is where we load the relationship resource:
            'post_metas' => PostMetaResource::collection($this->whenLoaded('post_metas')),
        ];
    }
}

Applying them

use App\Http\Resources\PostResource;

//

public function index(Request $request)
{
    $posts = Post::with('post_metas')->get();

    return PostResource::collection($posts);
}
Related