Laravel updateOrCreate with composite key - laravel

I have a table that's defined thus:
Schema::create('tableA', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->integer('label_id')->unsigned();
$table->date('date');
$table->integer('value');
$table->unique(['user_id','label_id','date']);
$table->timestamps();
});
The table uses a composite key of user_id, label_id and date.
I would like to update the table using the Model::updateOrCreate method thus:
Model::updateOrCreate(
[
'user_id' => $user_id,
'label_id' => $label_id,
'date' => $date,
'value' => $value,
]);
But I get an error if I run the method when a row with the composite key already exists because it seems Laravel doesn't work with composite keys.
For example row
[
user_id:2,
label_id:3,
date:'2019-04-04',
value: 44
]
cannot be updated using
Model::updateOrCreate([
user_id:2,
label_id:3,
date:'2019-04-04',
value: 100
]);
Does this mean there's no way to use updateOrCreate and I need to check each row if it exists before I attempt to add it ?

If you want to update a row based on a user_id the first parameter of the updateOrCreate is an array of fields you are looking to match, and the second contains fields that should update. So from what you are saying I believe you should use this:
Model::updateOrCreate([
user_id => 2,
label_id => 3,
date => new Carbon('2019-04-04')
],
[
value => 100
]);

Related

How to fix upsert problem when seeding? (laravel)

I have these code below, all seems working but when I try to run unit test it returns an error below.
Here is my seeder (this seeder is called many times in different test cases):
DB::table('sizes')->upsert([
[
'name' => 'jumbo',
'created_at' => date("Y-m-d H:i:s"),
'updated_at' => date("Y-m-d H:i:s"),
],
[
'name' => 'large',
'created_at' => date("Y-m-d H:i:s"),
'updated_at' => date("Y-m-d H:i:s"),
]
], ['id'], ['name']);
And the errors pops out:
Illuminate\Database\QueryException: SQLSTATE[23000]: Integrity constraint violation: 19 UNIQUE constraint failed: sizes.name (SQL: insert into "sizes" ("created_at", "name", "updated_at") values (2021-05-10 12:52:18, jumbo, 2021-05-10 12:52:18), (2021-05-10 12:52:18, large, 2021-05-10 12:52:18) on conflict ("id") do update set "name" = "excluded"."name")
Here is the migration:
Schema::create('sizes', function (Blueprint $table) {
$table->id();
$table->string('name')
->unique();
$table->timestamps();
});
Your migration will result in such table:
id INT AUTO_INCREMENT PRIMARY_KEY
name VARCHAR UNIQUE
created_at TIMESTAMP
updated_at TIMESTAMP
Your seeder when run first time will insert such records:
id
name
created_at
updated_at
1
jumbo
...
...
2
large
...
...
Now, based on laravel's documentation on upsert:
If you would like to perform multiple "upserts" in a single query, then you should use the upsert method instead.
The method's first argument consists of the values to insert or update, while the second argument lists the column(s) that uniquely identify records within the associated table.
The method's third and final argument is an array of the columns that should be updated if a matching record already exists in the database.
The upsert method will automatically set the created_at and updated_at timestamps if timestamps are enabled on the model:
The important point is:
The method's first argument consists of the values to insert or update,
while the second argument lists the column(s) that uniquely identify records within the associated table.
The method's third and final argument is an array of the columns that should be updated if a matching record already exists in the database
That means, your command:
DB::table('sizes')->upsert([
[
'name' => 'jumbo',
'created_at' => date("Y-m-d H:i:s"),
'updated_at' => date("Y-m-d H:i:s"),
],
[
'name' => 'large',
'created_at' => date("Y-m-d H:i:s"),
'updated_at' => date("Y-m-d H:i:s"),
]
], ['id'], ['name']);
Will do this:
check if any record have id of (blank) => no record will match (so upsert will become insert instead)
insert into database, value name=jumbo, and insert into database, value name=large,
this second step will fail since there's already record on database that have name=jumbo (and another record with name=large)
remember that you have name VARCHAR UNIQUE constraint, and this second step violates the UNIQUE constraint
Instead, you should change your seeder into this:
DB::table('sizes')->upsert([
[
'name' => 'jumbo',
'created_at' => date("Y-m-d H:i:s"),
'updated_at' => date("Y-m-d H:i:s"),
],
[
'name' => 'large',
'created_at' => date("Y-m-d H:i:s"),
'updated_at' => date("Y-m-d H:i:s"),
]
], ['name'], ['created_at','updated_at']);
The edited version will do this:
check if any record have name of "jumbo"
no record will match initially (so upsert will become insert first time),
and for subsequent run will match (so upsert will become update for subsequent runs)

Field 'id' doesn't have a default value when import excel file laravel

return new hasilsurvey([
'survey' => $row[1],
'question1' => $row[2],
'question2' => $row[3],
]);
I has setting my table columns 'id' to primary key but still get same problem
Please help my problem
When creating your migration you must define id field as autoincrement:
$table->bigIncrements('id');
If you want to update id field for that table you can do it with this:
$table->bigIncrements('id')->change();

SQLSTATE[HY000]: General error: 1 table tags has no column named 0

I'm trying to seed data into tags table my schema is as follows:
Schema::create('tags',function (Blueprint $table){
$table->bigIncrements('id');
$table->string('tag_name');
});
my seed is as follows:
public function run()
{
$array=array(
array(
'computer'
),
array(
'hp'
),
array(
'mac'
)
);
DB::table('tags')->insert($array);
}
The array of data to insert into the database is an associative array where the keys are the columns to be set with corresponding values:
['field' => $value, 'other_field' => $otherValue]
If you bulk inserting you will have an array containing arrays of values to insert:
[['tag_name' => 'computer'], ['tag_name' => 'hp'], ...]
Currently you have zero indexed arrays:
[[0 => 'computer'], [0 => 'hp'], ...]
So it is trying to set a column named 0.
Laravel 6.x Docs - Query Builder - Inserts

Insert null in date field in postgresql using collection

I am trying to insert an array with date field - end_date in postgresql with Laravel 5.7. But this gives an error -
SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column \"end_date\" violates not-null constraint
I am using Laravel 5.7, Postgresql 9.3
$array = [
"amazon_store_id" => 4
"advertising_profile_id" => 1
"campaign_id" => 123
"name" => "6 shelf 2"
"campaign_type" => "sponsoredProducts"
"targeting_type" => "manual"
"premium_bid_adjustment" => true
"daily_budget" => 15.0
"start_date" => "2014-11-25 09:32:18"
"end_date" => null
"state" => "paused"
"serving_status" => "CAMPAIGN_PAUSED"
"creation_date" => "2014-11-07 10:17:03"
"last_updated_date" => "2018-10-24 12:49:54"
"created_at" => "2018-12-24 09:32:18"
"updated_at" => "2018-12-24 09:32:18"
];
DB::table($table_name)->insert($array->toArray());
Ideally it shall insert the null in the database.
In your migration you can do this to make the column nullable:
public function up()
{
Schema::create('tablename', function (Blueprint $table) {
$table->dateTime('end_date')->nullable();
});
}
->nullable() Designate that the column allows NULL values
In your migration file you have to define the date field as nullable.
Schema::table($table_name, function (Blueprint $table) {
$table->dateTime('end_date')->nullable();
});

Laravel relationship with method "with" returns null

Today I wanted to do some clean code so just started selecting columns for with relationship. With this code:
\App\Genre::with([
'family'
])->where([
'slug' => $slug,
'is_active' => true
])->first();
everything is working fine. But when I start selecting columns for "with" method:
\App\Genre::with([
'family' => function ($query) {
$query->select('name_pl', 'name_lat');
}])->where([
'slug' => $slug,
'is_active' => true
])->first();
I got that family is null (but it should be an object with columns: name_pl, name_lat). What I am doing wrong?
family method in Genre class looks like this:
public function family () {
return $this->belongsTo(Family::class);
}
I am using Laravel 5.4
Pretty sure you need to add a related column to the list of selected columns, otherwise Laravel won't b able to match the data to eager-load.
Assuming that Genre has a family_id and Family has an id primary key column specified, you need this:
$query->select('id', 'name_pl', 'name_lat'); // See the id added here?
Should do the trick.
For clarity, the matching I mentioned is this one:
select * from genre
select * from family where id in (1, 2, 3, 4, 5, ...)
-- where the comma-separated list of IDs consists of the unique family_id values retrieved in the first query.
Why don't you try:
\App\Genre::with('family:name_pl,name_lat')->where([
'slug' => $slug,
'is_active' => true
])->first();

Resources