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

madsynn's avatar

Guidance With using UPSERT

I have a question how would I format UPSERT to insert into 3 tables from each row coming from external post request with the following example.


collect($request->all())
->map(function (array $row) {
    return Arr::only($row, 
    [
      'email' => $row['email'], 
      'name' => $row['name'], 
      'address' => $row['address'],
      ],
    [
      'role'  => $row['role'],
    ],
    [ // need some way to foreach or something here
      name => $row['name'],
      name => $row['name'],
      name => $row['name'],
    ]
  )
})
->chunk(100)
->each(function (Collection $chunk) {
    Contact::upsert($chunk, 'email');
    Role::upsert($chunk, 'role');
    Permission::upsert($chunk, 'name');
});

0 likes
3 replies
EnterUsername's avatar

Your code snipplet is confusing, could you show the original data from $request->all() and give an example of how you want it inserted

madsynn's avatar

@enterusername

Thanks I am trying to use the new upsert for laravel along with collection. I normally would use updateOrInsert([identifier], [insertorupate]). but this new way has advantages over the other. Also I like to learn better ways to do things and I appreciate your help.

Request->all() would come from a post would look like this.

[
   {
      "data":[
         {
            "email":"[email protected]",
            "published":"1",
            "name":"Name 1",
            "address":"address1, city1, state1, zip1",
            "role":"editor",
            "permissions":["can_access,can_edit"]
         },
         {
            "email":"[email protected]",
            "published":"1",
            "name":"Name 2",
            "address":"address2, city2, state2, zip2",
            "role":"manager",
            "permissions":["can_access,can_create,can_edit,can_delete"]
         },
         {
            "email":"[email protected]",
            "published":"1",
            "name":"Name 3",
            "address":"address3, city3, state3, zip3",
            "role":"editor",
            "permissions":["can_access,can_edit"]
         },
         {
            "email":"[email protected]",
            "published":"0",
            "name":"Name 4",
            "address":"address4, city4, state4, zip4",
            "role":"editor",
            "permissions":["can_access,can_edit"]
         },
         {
            "email":"[email protected]",
            "published":"1",
            "name":"Name 5",
            "address":"address5, city5, state5, zip5",
            "role":"admin",
            "permissions":["can_access,can_create,can_edit,can_delete,manage_users,create_users,edit_users,delete_users"]
         }
      ]
   }
]

3 Models and columns:

User::
    email
    published
    name
    address

Role::
  role
   
Permission::
  name
 
User -> belongsTo -> Role
User -> hasMany   -> Permissions

To answer the update Or Insert I am trying to insert email, published,name, address into users table, role into roles table, and permissions into permissions table.

EnterUsername's avatar
Level 1

Thanks.

A good rule of thumb when attempting to try something new is to

  1. Make it work
  2. Optimize if needed for readability and or speed.

After I created the code example I realized your user "hasMany" permissions and not "belongsToMany", which causes this code to not work, you would need to change the relationship to a "belongsToMany" relationship, the docs has great documentation for this.

collect($request->all())
        ->each(function ($row) {
            collect($row['data'])->each(function ($row) {
                /*
                 * Convert array to collection
                 */
                $row = collect($row);
                /*
                 * Create user if needed (the email field is determined to see if the user exists or not)
                 */
                $user = \App\Models\User::firstOrCreate(
                    $row->only('email'),
                    $row->only(['published', 'name', 'address'])
                );
                /*
                 * Here we do the same thing for the Role
                 */
                $role = \App\Models\Role::firstOrCreate($row->only(['role']));
                /*
                 * "permissions" => array:1 [
                 *   0 => "can_access,can_edit"
                 * ]
                 */
                $permissionIds = collect($row->get('permissions'))->map(function ($permissionStr) {
                    // $permissionStr is "can_access,can_edit" etc
                    $ids = [];
                    // explode string
                    $permissionArr = explode(',', $permissionStr);
                    // Create each access property and return it
                    foreach ($permissionArr as $name) {
                        $ids[] = \App\Models\Permission::firstOrCreate(['name' => $name])->id;
                    }
                    return $ids;
                })
                    ->flatten(1) // because this array will be nested we have to flatten it. AKA [[1,2], [1,2]] => [1,2,1,2]
                    ->unique(); // remove duplicates. AKA [1,2,1,2] => [1,2]
                /*
                 * Set the role id and save the model
                 */
                $user->role_id = $role->id;
                $user->save();
                /*
                 * Attach permissions by ID
                 */
                $user->Permissions()->sync($permissionIds);
                /*
                 * We are now done!
                 */
            });
        });

Please or to participate in this conversation.