[php] Creating and Update Laravel Eloquent

What's the shorthand for inserting a new record or updating if it exists?

<?php

$shopOwner = ShopMeta::where('shopId', '=', $theID)
    ->where('metadataKey', '=', 2001)->first();

if ($shopOwner == null) {
    // Insert new record into database
} else {
    // Update the existing record
}

This question is related to php laravel eloquent laravel-query-builder

The answer is


Isn't this the same as updateOrCreate()?

It is similar but not the same. The updateOrCreate() will only work for one row at a time which doesn't allow bulk insert. InsertOnDuplicateKey will work on many rows.

https://github.com/yadakhov/insert-on-duplicate-key


If you need the same functionality using the DB, in Laravel >= 5.5 you can use:

DB::table('table_name')->updateOrInsert($attributes, $values);

or the shorthand version when $attributes and $values are the same:

DB::table('table_name')->updateOrInsert($values);

Like the firstOrCreate method, updateOrCreate persists the model, so there's no need to call save()

// If there's a flight from Oakland to San Diego, set the price to $99.
// If no matching model exists, create one.

$flight = App\Flight::updateOrCreate(
   ['departure' => 'Oakland', 'destination' => 'San Diego'],
   ['price' => 99]
);

And for your issue

$shopOwner = ShopMeta::updateOrCreate(
   ['shopId' => $theID, 'metadataKey' => '2001'],
   ['other field' => 'val' ,'other field' => 'val', ....]
);

2020 Update

As in Laravel >= 5.3, if someone is still curious how to do so in easy way. Its possible by using : updateOrCreate().

For example for asked question you can use something like:

$matchThese = ['shopId'=>$theID,'metadataKey'=>2001];
ShopMeta::updateOrCreate($matchThese,['shopOwner'=>'New One']);

Above code will check the table represented by ShopMeta, which will be most likely shop_metas unless not defined otherwise in model itself

and it will try to find entry with

column shopId = $theID

and

column metadateKey = 2001

and if it finds then it will update column shopOwner of found row to New One.

If it finds more than one matching rows then it will update the very first row that means which has lowest primary id.

If not found at all then it will insert a new row with :

shopId = $theID,metadateKey = 2001 and shopOwner = New One

Notice Check your model for $fillable and make sue that you have every column name defined there which you want to insert or update and rest columns have either default value or its id column auto incremented one.

Otherwise it will throw error when executing above example:

Illuminate\Database\QueryException with message 'SQLSTATE[HY000]: General error: 1364 Field '...' doesn't have a default value (SQL: insert into `...` (`...`,.., `updated_at`, `created_at`) values (...,.., xxxx-xx-xx xx:xx:xx, xxxx-xx-xx xx:xx:xx))'

As there would be some field which will need value while inserting new row and it will not be possible as either its not defined in $fillable or it doesnt have default value.

For more reference please see Laravel Documentation at : https://laravel.com/docs/5.3/eloquent

One example from there is:

// If there's a flight from Oakland to San Diego, set the price to $99.
// If no matching model exists, create one.
$flight = App\Flight::updateOrCreate(
    ['departure' => 'Oakland', 'destination' => 'San Diego'],
    ['price' => 99]
);

which pretty much clears everything.

Query Builder Update

Someone has asked if it is possible using Query Builder in Laravel. Here is reference for Query Builder from Laravel docs.

Query Builder works exactly the same as Eloquent so anything which is true for Eloquent is true for Query Builder as well. So for this specific case, just use the same function with your query builder like so:

$matchThese = array('shopId'=>$theID,'metadataKey'=>2001);
DB::table('shop_metas')::updateOrCreate($matchThese,['shopOwner'=>'New One']);

Of course, don't forget to add DB facade:

use Illuminate\Support\Facades\DB;

OR

use DB;

I hope it helps


Updated: Aug 27 2014 - [updateOrCreate Built into core...]

Just in case people are still coming across this... I found out a few weeks after writing this, that this is in fact part of Laravel's Eloquent's core...

Digging into Eloquent’s equivalent method(s). You can see here:

https://github.com/laravel/framework/blob/4.2/src/Illuminate/Database/Eloquent/Model.php#L553

on :570 and :553

    /**
     * Create or update a record matching the attributes, and fill it with values.
     *
     * @param  array  $attributes
     * @param  array  $values
     * @return static
     */
    public static function updateOrCreate(array $attributes, array $values = array())
    {
        $instance = static::firstOrNew($attributes);

        $instance->fill($values)->save();

        return $instance;
    }

Old Answer Below


I am wondering if there is any built in L4 functionality for doing this in some way such as:

$row = DB::table('table')->where('id', '=', $id)->first();
// Fancy field => data assignments here
$row->save();

I did create this method a few weeks back...

// Within a Model extends Eloquent
public static function createOrUpdate($formatted_array) {
    $row = Model::find($formatted_array['id']);
    if ($row === null) {
        Model::create($formatted_array);
        Session::flash('footer_message', "CREATED");
    } else {
        $row->update($formatted_array);
        Session::flash('footer_message', "EXISITING");
    }
    $affected_row = Model::find($formatted_array['id']);
    return $affected_row;
}

I Hope that helps. I would love to see an alternative to this if anyone has one to share. @erikthedev_


$shopOwner = ShopMeta::firstOrNew(array('shopId' => $theID,'metadataKey' => 2001));

Then make your changes and save. Note the firstOrNew doesn't do the insert if its not found, if you do need that then its firstOrCreate.


One more option if your id isn't autoincrement and you know which one to insert/update:

$object = MyModel::findOrNew($id);
//assign attributes to update...
$object->save();

like @JuanchoRamone posted above (thank @Juancho) it's very useful for me, but if your data is array you should modify a little like this:

public static function createOrUpdate($data, $keys) {
    $record = self::where($keys)->first();
    if (is_null($record)) {
        return self::create($data);
    } else {
        return $record->update($data);
    }
}

Actually firstOrCreate would not update in case that the register already exists in the DB. I improved a bit Erik's solution as I actually needed to update a table that has unique values not only for the column "id"

/**
 * If the register exists in the table, it updates it. 
 * Otherwise it creates it
 * @param array $data Data to Insert/Update
 * @param array $keys Keys to check for in the table
 * @return Object
 */
static function createOrUpdate($data, $keys) {
    $record = self::where($keys)->first();
    if (is_null($record)) {
        return self::create($data);
    } else {
        return self::where($keys)->update($data);
    }
}

Then you'd use it like this:

Model::createOrUpdate(
        array(
    'id_a' => 1,
    'foo' => 'bar'
        ), array(
    'id_a' => 1
        )
);

firstOrNew will create record if not exist and updating a row if already exist. You can also use updateOrCreate here is the full example

$flight = App\Flight::updateOrCreate(
    ['departure' => 'Oakland', 'destination' => 'San Diego'],
    ['price' => 99]
); 

If there's a flight from Oakland to San Diego, set the price to $99. if not exist create new row

Reference Doc here: (https://laravel.com/docs/5.5/eloquent)


Try more parameters one which will surely find and if available update and not then it will create new

$save_data= Model::firstOrNew(['key1' => $key1value,'key'=>$key2value]);
//your values here
$save_data->save();

Save function:

$shopOwner->save()

already do what you want...

Laravel code:

    // If the model already exists in the database we can just update our record
    // that is already in this database using the current IDs in this "where"
    // clause to only update this model. Otherwise, we'll just insert them.
    if ($this->exists)
    {
        $saved = $this->performUpdate($query);
    }

    // If the model is brand new, we'll insert it into our database and set the
    // ID attribute on the model to the value of the newly inserted row's ID
    // which is typically an auto-increment value managed by the database.
    else
    {
        $saved = $this->performInsert($query);
    }

check if a user exists or not. If not insert

$exist = DB::table('User')->where(['username'=>$username,'password'=>$password])->get();
if(count($exist)  >0) {
    echo "User already exist";;
}
else  {
    $data=array('username'=>$username,'password'=>$password);
    DB::table('User')->insert($data);
}
Laravel 5.4           

Examples related to php

I am receiving warning in Facebook Application using PHP SDK Pass PDO prepared statement to variables Parse error: syntax error, unexpected [ Preg_match backtrack error Removing "http://" from a string How do I hide the PHP explode delimiter from submitted form results? Problems with installation of Google App Engine SDK for php in OS X Laravel 4 with Sentry 2 add user to a group on Registration php & mysql query not echoing in html with tags? How do I show a message in the foreach loop?

Examples related to laravel

Parameter binding on left joins with array in Laravel Query Builder Laravel 4 with Sentry 2 add user to a group on Registration Target class controller does not exist - Laravel 8 Visual Studio Code PHP Intelephense Keep Showing Not Necessary Error The POST method is not supported for this route. Supported methods: GET, HEAD. Laravel How to fix 'Unchecked runtime.lastError: The message port closed before a response was received' chrome issue? Post request in Laravel - Error - 419 Sorry, your session/ 419 your page has expired Expected response code 250 but got code "530", with message "530 5.7.1 Authentication required How can I run specific migration in laravel Laravel 5 show ErrorException file_put_contents failed to open stream: No such file or directory

Examples related to eloquent

Eloquent: find() and where() usage laravel How to select specific columns in laravel eloquent Laravel Eloquent where field is X or null Laravel Eloquent limit and offset laravel collection to array Eloquent get only one column as an array Laravel 5.2 - Use a String as a Custom Primary Key for Eloquent Table becomes 0 Laravel 5.2 - pluck() method returns array Eloquent ORM laravel 5 Get Array of ids eloquent laravel: How to get a row count from a ->get()

Examples related to laravel-query-builder

Get Specific Columns Using “With()” Function in Laravel Eloquent How to Create Multiple Where Clause Query Using Laravel Eloquent? Creating and Update Laravel Eloquent How Do I Get the Query Builder to Output Its Raw SQL Query as a String? How to Use Order By for Multiple Columns in Laravel 4? Laravel 4 Eloquent Query Using WHERE with OR AND OR? A JOIN With Additional Conditions Using Query Builder or Eloquent Get the Query Executed in Laravel 3/4