Home > Blockchain >  Convert many:many response into single objects
Convert many:many response into single objects

Time:08-30

I have defined a users table, a roles table and a user_role pivot in my database. The model for the user is as follows:

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    //... Fields defined here

    public function roles()
    {
        return $this->belongsToMany(Role::class, 'user_role');
    }
}

Inside the role model, I have this also:

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Role extends Model
{
    //... Fields defined here
    public function users()
    {
        return $this->belongsToMany(User::class, 'user_role');
    }
}

Now here lies the problem. When I run the following in the API routes (relatively crude)

$user_roles = \App\Models\User::with('roles')->get();

I get a list of all the users, with each array having an internal array of all the roles. I will like the results such that each user will have one role and if there are multiple roles, I duplicate the user with this new role.

How is this achieved? Thanks in advance for the assistance

CodePudding user response:

You can do something like flatMap:

$user_roles = \App\Models\User::with('roles')->get()
   ->flatMap(function ($user) {
      if ($user->roles->isEmpty()) { return $user; }
      return $user->roles->map(function ($role) use ($user) { 
            $newUser = clone $user;
            $newUser->roles = $role;
            return $newUser;
      });
   });

An alternative is to use a join instead of an eloquent relationship e.g.:

$user_roles = DB::table('users')
    ->join('user_role', 'user_role.user_id', 'user.id')
    ->join('roles', 'user_role,role_id', 'roles.id')
    ->selectRaw('users.*, roles.*')->get();

This should result in a result of users and roles combined in one object.

  • Related