Run Update query in a migration in Laravel 5? [duplicate] - php

I need to add a new column in my laravel Project, no problem for this, I used the Schema::table() to update and it's ok.
Now I need to find out how many records I have on this table and update with some value.
I have the table Warrants:
Schema::create('warrant_grants', function(Blueprint $table) {
$table->increments('id');
$table->integer('warrant_plan_id');
$table->integer('shareholder_id');
});
So I created the new field with a new migration file:
Schema::table('warrant_grants',function ($table) {
$table->string('name',100);
});
Now I need to update this field name in the table with some values, for example if the table has 100 records, then I need to insert in every row the value "Warrant-X" where X is a number starting with 1 to 100.
For example:
Warrant-1, Warrant-2, ....Warrant-100.
I spent hours looking for some way to do this using Seeds but I didn't found. So basically i have two questions:
Can I use Seeds in Laravel 5 to update values or I can just insert them?
Can I create some SQL inside the Seeds (or migrations) to do this update for me?

Based on this link i found the answer: https://stackoverflow.com/a/23506744/4650792
Schema::table('warrant_grants',function ($table){
$table->string('name',100)->after('id')->nullable();
});
$results = DB::table('warrant_grants')->select('id','name')->get();
$i = 1;
foreach ($results as $result){
DB::table('warrant_grants')
->where('id',$result->id)
->update([
"name" => "Warrant-".$i
]);
$i++;
}
Thanks for the help anyway guys.

Other answers are correct. But note that if you have a lot of records, updating all of them with ORM can take time. Use raw SQL queries to do that faster.
Schema::table('warrant_grants',function ($table){
$table->string('name',100)->after('id')->nullable();
});
DB::raw("UPDATE warrant_grants SET name=name+id");
The SQL query is not exact, and you have to make it for your own DB, but you get the point.

Yes, you can perform updates/inserts/whatever in your migrations. For example:
Schema::table('warrant_grants', function($table) {
$table->string('name', 100);
});
$i = 1;
foreach (WarrantGrants::all() as $warrant_grant) {
$warrant_grant->update([
'name' => 'Warrant-' . $i
]);
$i++;
}

Another possible syntax to achieve this:
DB::table('warrant_grants')
->where('id',$result->id)
->update([
"name" => DB::raw("'Warrant-' + `name`")
]);
This allows the update to be done as one batch rather than iterating over results, and retains most of the familiar Eloquent syntax rather than falling back to just using raw SQL.
The string concatenation syntax may need to be changed depending on the SQL variant used.

Related

Can't update column 'Updated_at' in laravel eloquent

I'm still new to this laravel framework, so I was having this issue where I was unable to update the column "updated_at" which is automatically created by laravel migration. I want to change the value to the current time when I press a button. I have tried multiple ways from similar questions but it doesn't seem to work, like using '->update()','->save()', or '->touch()'.
syntax to update in Controller
$check = \DB::table('queueTable')->where('category',$catName2)->where('status','Active')->where('skipped','0')->whereDate('created_at','=',now())->orderBy('queue','ASC')->limit(1);
$counter = \DB::table('queueTable')->where('category',$catName2)->where('status','Inactive')->whereDate('created_at','=',now())->count();
\DB::table('CurrentQueue')->where('id', 2)->update(['DoneQueue' => $counter+1]);
$check->update(['status' => 'Inactive']);
$check->update(['updated_at' => now()->format('Y-m-d H:i:s')]);
my migration
Schema::create('queueTable', function (Blueprint $table) {
$table->id();
$table->string('category');
$table->integer('queue')->default('0');
$table->string('status');
$table->integer('skipped')->default('0');
$table->timestamps();
});
it'd be much appreciated if someone could kindly explain where I'm going wrong.
Thanks in advance.
I want to update the value of "updated_at" to the current time when I press a button
Update you record using Model, it will update "updated_at" automatically.
Change code i your controller:
$check = queueTable::where('category',$catName2)->where('status','Active')->where('skipped','0')->whereDate('created_at','=',now());
$counter = $check->count();
$check = ->orderBy('queue','ASC')->first();
CurrentQueue::where('id', 2)->save(['DoneQueue' => $counter+1]);
$check->save(['status' => 'Inactive']);
Note: If you are not using model, first create Models queueTable, CurrentQueue

Using Laravel 5.5 how do I duplicate a column in a table with a migration?

I would like to duplicate a column on my existing seasons table using a migration in Laravel 5.5.
I can do it using SQL running these two queries:
ALTER TABLE seasons ADD uploader_channel_partner_id BIGINT NULL
then
UPDATE seasons set seasons.uploader_channel_partner_id = seasons.channel_partner_id
I am creating a system where you can transfer the ownership of videos while keeping the original uploader stored.
The up function of my migration currently just has this inside it:
Schema::create('seasons', function (Blueprint $table) {
$table->unsignedBigInteger('uploader_channel_partner_id');
$table->foreign('uploader_channel_partner_id')->references('id')->on('channel_partners');
});
EDIT:
I've made it work with this but it's slow and ugly and I'm sure there is a better way:
public function up()
{
Schema::table('seasons', function (Blueprint $table) {
$table->unsignedBigInteger('uploader_channel_partner_id')->after('channel_partner_id')->nullable();
$table->foreign('uploader_channel_partner_id')->references('id')->on('channel_partners');
});
$seasons = Season::withTrashed()->get();
foreach ($seasons as $key => $season) {
$season->uploader_channel_partner_id = $season->channel_partner_id;
$season->save();
}
}
You can use DB::raw() to force Sql to use another column instead of a string value.
Season::withTrashed()
->update([
'uploader_channel_partner_id' => DB::raw('`channel_partner_id`'),
]);

Laravel scoreboard of more than 1 million users

I'm working in a biggest application ( more than 1 million users ) and I try to get the ranking of each user in the scoreboard section but had this problem: the result is very very slow
This is the architecture of my database:
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
...
});
Schema::create('topics', function (Blueprint $table) {
$table->increments('id');
...
});
The topics table have than 20 row
Schema::create('user_scores', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->integer('topic_id')->unsigned();
$table->unique(['user_id', 'topic_id']);
$table->float('timer');
$table->integer('score');
});
The query to make rank for users
User::where('type',0)->get()->each(function ($user) {
$user->topics= $user->scores->sum('score');
$user->timing= $user->scores->sum('timer');
})->sort(function ($a, $b){
return ($b->topics - $a->topics) == 0
? ($a->timing - $b->timing)
: ($b->topics - $a->topics);
})->values()->each(function($user, $key){
$user->rank = $key +1;
});
Any optimization should I make the get the result quicker? Thanks.
As soon as you call get(), all(), find() or first() on a query builder, you'll ask the Eloquent engine to perform the query and return you the result. So in your case, all the sorting and grouping is performed in memory, which comes with incredibly bad performance.
What you can do is to improve your query:
User::query()
->where('type', 0)
->withCount('scores as topics')
->withCount(['scores as timing' => function ($query) {
$query->selectRaw('SUM(timer)'); // might look weird, but works...
}])
->orderBy('topics', 'desc')
->orderBy('timing', 'desc')
->get()
For the row number (or rank, or however you wanna call it), you might want to search through existing questions and answers. Answering that as well would be too much for this answer, to be honest. Clearly you should not use your approach though, as it will also calculate the row number in memory.
But obviously it is also important what you are doing with the query results. Are you displaying one million rows to the user? If so, the bottleneck will be the browser in the end for sure. You might want to consider using pagination with paginate() instead of get().

Best practices to update a collection [duplicate]

I'm trying to make a notification system with laravel. My idea was to get data and update instantly the "is_delivered" flag.
This is the code:
Model:
public function scopeGetForView($query)
{
$query->orderBy('created_at','DESC');
$return = $query->get();
if($return->count() > 0) {
$query->update(array("is_delivered" => 1));
}
return $return;
}
Controller:
$notifications = Auth::user()->notifications()->limit(10)->offset(10)->getForView();
Well, this would work fine without the offset because MySQL does only support limit (without offset) when updating.
But how can I update the whole collection without looping through it? Looping with instant updating would lead to many queries. The other way I can think of would be to create an array with IDs and update them with whereIn(). Is this the only way doing it?
You can run an update on the whole collection:
DB::table('table_name')->whereIn('id', $collection->modelKeys())->update(['is_delivered' => 1]);

PHP Laravel 5.4.21. Eloquent save insert in first row

I have a problem with saving Eloquent models. For example:
$game = Game::select(['bank', 'state', 'quantity_of_players'])->find($id)->first();
$game->bank += $game->bet;
$game->quantity_of_players++;
$game->save();
As far as i know from documentation, save() should insert changed values in a row with $id, but instead it inserts in a very first row. What's an issue, and how to save it properly to my database in specified row.
Migration for this model:
public function up()
{
Schema::create('games', function (Blueprint $table) {
$table->bigIncrements('id');
$table->enum('state', ['wait', 'search', 'accept', 'play', 'finish']);
$table->smallInteger('quantity_of_players');
$table->smallInteger('ready_players');
$table->smallInteger('finished_players');
$table->integer('bank');
$table->smallInteger('bet');
});
}
Would really appreciate any help with this.
P.S. All SELECT requests works perfectly such as Eloquent create().
The find() method internally calls first(). It's also a good practise to check if the row exists before proceeding. Using findOrFail() does this for you.
$game = Game::findOrFail($id);
$game->bank += $game->bet;
$game->quantity_of_players++;
$game->save();
Edit
If you're insistent on selecting the columns even for the update. Then do this
$game = Game::whereId($id)->first(['bank', 'state', 'quantity_of_players']);
Please try the following
$game = Game::find($id);
$game->bank += $game->bet;
$game->quantity_of_players++;
$game->save();

Categories