How to insert big data on the laravel? - laravel

I am using laravel 5.6
My script to insert big data is like this :
...
$insert_data = [];
foreach ($json['value'] as $value) {
$posting_date = Carbon::parse($value['Posting_Date']);
$posting_date = $posting_date->format('Y-m-d');
$data = [
'item_no' => $value['Item_No'],
'entry_no' => $value['Entry_No'],
'document_no' => $value['Document_No'],
'posting_date' => $posting_date,
....
];
$insert_data[] = $data;
}
\DB::table('items_details')->insert($insert_data);
I have tried to insert 100 record with the script, it works. It successfully insert data
But if I try to insert 50000 record with the script, it becomes very slow. I've waited about 10 minutes and it did not work. There exist error like this :
504 Gateway Time-out
How can I solve this problem?

As it was stated, chunks won't really help you in this case if it is a time execution problem. I think that bulk insert you are trying to use cannot handle that amount of data , so I see 2 options:
1 - Reorganise your code to properly use chunks, this will look something like this:
$insert_data = [];
foreach ($json['value'] as $value) {
$posting_date = Carbon::parse($value['Posting_Date']);
$posting_date = $posting_date->format('Y-m-d');
$data = [
'item_no' => $value['Item_No'],
'entry_no' => $value['Entry_No'],
'document_no' => $value['Document_No'],
'posting_date' => $posting_date,
....
];
$insert_data[] = $data;
}
$insert_data = collect($insert_data); // Make a collection to use the chunk method
// it will chunk the dataset in smaller collections containing 500 values each.
// Play with the value to get best result
$chunks = $insert_data->chunk(500);
foreach ($chunks as $chunk)
{
\DB::table('items_details')->insert($chunk->toArray());
}
This way your bulk insert will contain less data, and be able to process it in a rather quick way.
2 - In case your host supports runtime overloads, you can add a directive right before the code starts to execute :
ini_set('max_execution_time', 120 ) ; // time in seconds
$insert_data = [];
foreach ($json['value'] as $value)
{
...
}
To read more go to the official docs

It makes no sense to use an array and then convert it to a collection.
We can get rid of arrays.
$insert_data = collect();
foreach ($json['value'] as $value) {
$posting_date = Carbon::parse($value['Posting_Date']);
$posting_date = $posting_date->format('Y-m-d');
$insert_data->push([
'item_no' => $value['Item_No'],
'entry_no' => $value['Entry_No'],
'document_no' => $value['Document_No'],
'posting_date' => $posting_date,
....
]);
}
foreach ($insert_data->chunk(500) as $chunk)
{
\DB::table('items_details')->insert($chunk->toArray());
}

Here is very good and very Fast Insert data solution
$no_of_data = 1000000;
$test_data = array();
for ($i = 0; $i < $no_of_data; $i++){
$test_data[$i]['number'] = "1234567890";
$test_data[$i]['message'] = "Test Data";
$test_data[$i]['status'] = "Delivered";
}
$chunk_data = array_chunk($test_data, 1000);
if (isset($chunk_data) && !empty($chunk_data)) {
foreach ($chunk_data as $chunk_data_val) {
DB::table('messages')->insert($chunk_data_val);
}
}

I used the code below to check the update or insert data of 11 thousand rows. I hope it useful for you.
$insert_data = [];
for ($i=0; $i < 11000; $i++) {
$data = [
'id' =>'user_'.$i,
'fullname' => 'Pixs Nguyen',
'username' => 'abc#gmail.com',
'timestamp' => '2020-03-23 08:12:00',
];
$insert_data[] = $data;
}
$insert_data = collect($insert_data); // Make a collection to use the chunk method
// it will chunk the dataset in smaller collections containing 500 values each.
// Play with the value to get best result
$accounts = $insert_data->chunk(500);
// In the case of updating or inserting you will take about 35 seconds to execute the code below
for ($i=0; $i < count($accounts); $i++) {
foreach ($accounts[$i] as $key => $account)
{
DB::table('yourTable')->updateOrInsert(['id'=>$account['id']],$account);
}
}
// In the case of inserting you only take about 0.35 seconds to execute the code below
foreach ($accounts as $key => $account)
{
DB::table('yourTable')->insert($account->toArray());
}

Related

How to properly update a array that has only one identifying id

I'm trying to update an array with objects inside something like this, with the current code I have it only saves the first one, I know that's the problem but I don't know how to fix it
array (
0 =>
array (
'option' => 'new',
),
1 =>
array (
'option' => 'ewrwer',
),
),
This is my current code, the line in question is
$option = SurveyQuestionOption::where('survey_question_id', $preg->id)->first();
How do I fix this so it cycles through all in the array questionOptions instead of just the first one? I tried ->get() but then the ->save() doesn't work.
public function update(Request $request, $id)
{
DB::beginTransaction();
$preg = SurveyQuestion::findOrFail($id);
$preg->question = $request->question;
$preg->survey_section_id = $request->survey_section_id;
$preg->response_type_id = $request->response_type_id;
$preg->optional = $request->optional;
$preg->save();
$ids = [];
if ($request->get('questionOptions')) {
foreach ($request->get('questionOptions') as $item) {
$option = SurveyQuestionOption::where('survey_question_id', $preg->id)->first();
if (empty($option)) {
$option = new SurveyQuestionOption();
$option->survey_question_id = $preg->id;
}
$option->option = $item['option'];
$option->save();
}
}
if (count($ids) > 0) {
SurveyQuestionOption::whereNotIn('id', $ids)->where('survey_question_id', $preg->id)->delete();
}
DB::commit();
return back();
}
Basically, when you use get, you get a collection, so you can't really use save on it. you need to do a foreach loop, and save in that. i.e; like this;
$options = SurveyQuestionOption::where('survey_question_id', $preg->id)->get();
foreach($options as $option){
if (empty($option)) {
$option = new SurveyQuestionOption();
$option->survey_question_id = $preg->id;
}
$option->option = $item['option'];
$option->save();
}
Note that you can't save $options if you don't use a foreach loop, as you're not specifying which instance of the collection to save it in.

Batch insert in codeigniter

Hi I am quite new to cpdeignoter I just wanted to ask if I am doing the insert batch in ci right because it seemed not to work here is my controller
foreach($dat as $key => $val){
$data[] = array('ModelNumber' => $_POST['txt_model_num'][$key],
'Access' => $_POST['txt_accessories'][$key],
'SerialNumber' => $_POST['txt_snum'][$key],
'Charges' => $_POST['txt_charges'][$key],
'OtherRemarks' => $_POST['txt_rem'][$key],
'RequirementID' => $id1);
}
$cmd3 = $this->Software_model->add_type($data);
if($cmd3){
foreach($sql->result_array() as $row){
$id2 = $row['ID'];
}
$data2s = array();
foreach($dat as $key => $val){
$data2s[] = array('EquipmentName' => $_POST['txt_equipb'][$key],
'EquipmentType' => $_POST['txt_equiptype'][$key],
'RequirementID' => $id2);
}
$cmd2 = $this->Software_model->add_equip($data2s);
and this is the model
public function add_type($data)
{
return $this->db->insert_batch('jobtype', $data);
}
public function add_equip($data2s)
{
return $this->db->insert_batch('equipment', $data2s);
}
and the way I duplicate the textboxes in the views is like this
function second function(){
var etype = document.createElement('input');
etype.type = 'text';
etype.setAttribute("name", "txt_equiptype[]");
etype.setAttribute("class", "form-control");
etype.setAttribute("id", "etype");
etype.setAttribute("placeholder", "Enter Equipment Type");
document.getElementById('third').appendChild(etype);
}
thanks in advance
Hope this will help you :
Try out this alternate method :
foreach($dat as $key => $val)
{
$data[$key]['ModelNumber'] = $_POST['txt_model_num'][$key];
$data[$key]['Access'] = $_POST['txt_accessories'][$key];
$data[$key]['SerialNumber'] = $_POST['txt_snum'][$key];
$data[$key]['Charges'] = $_POST['txt_charges'][$key];
$data[$key]['OtherRemarks'] = $_POST['txt_rem'][$key];
$data[$key]['RequirementID'] = $id1;
}
/* Note : remove auto increment primary key from above array if you are including*/
user it for both the foreach

How to optimize code in Laravel?

I use the following code to get data from two related tables:
$arr = [];
$objectModel = new ProductCategory();
$objectModel::$language = 2;
$subcategories = $objectModel::with("translate", "parent")->get();
foreach($subcategories as $key => $item) {
$arr[$item->translate()->first()->objectId] = $item->translate()->first()->name;
}
array_unshift($arr, 'Select category');
return $arr;
In result this part of code I get array with key => value to insert this in select list in Blade template.
But I desire to escape a loop:
foreach($subcategories as $key => $item) {
$arr[$item->translate()->first()->objectId] = $item->translate()->first()->name;
}
And get clear collection from request. How can I do it?
You can use Laravel Collections https://laravel.com/docs/5.3/collections
$arr = ProductCategory::with("translate", "parent")->get()
->mapWithKeys(function ($item, $key) {
return [$item->translate()->first()->objectId => $item->translate()->first()->name];
})
->all();

Laravel, multiple file deleting in foreach

I wanna delete files from server by database ids.
I'm trying to do this in foreach loop.
Single file deleting is ok but, when user sends multiple file (by checkbox)
my loop deletes only first.
public function postSil(Request $request)
{
$ids = $request->input('sil');
foreach($ids as $id)
{
$file = File::find($id)->first();
$path = public_path().'/rea-files/'.$file->rea_number.'/'.$file->file_name;
\File::delete($path);
// echo 'id';
}
//return 1;
File::destroy($ids); //this is model file.
return redirect()->back();
}
As you can see, i tried if foreach loop works as well, placed echo and return and i see foreach loop is working but only deletes first file.
I have solved. I used array in File::delete()
just try below code
(case A) User fields indexed by number 0,1,2..
$users_to_delete = array(
'0'=> array('1','Frank','Smith','Whatever'),
'1'=> array('5','John','Johnson','Whateverelse'),
);
$ids_to_delete = array_map(function($item){ return $item[0]; }, $users_to_delete);
DB::table('users')->whereIn('id', $ids_to_delete)->delete();
//(case B) User fields indexed by key
$users_to_delete = array(
'0'=> array('id'=>'1','name'=>'Frank','surname'=>'Smith','title'=>'Whatever'),
'1'=> array('id'=>'5','name'=>'John','surname'=>'Johnson','title'=>'Whateverelse'),
);
$ids_to_delete = array_map(function($item){ return $item['id']; }, $users_to_delete);
DB::table('users')->whereIn('id', $ids_to_delete)->delete();
Case c
$ids = array( '0' => 1, '1' => 2);
DB::table('users')->whereIn('id',$ids)->delete();

codeigniter generating multiple pdfs

i'm trying to generates pdfs in loop against member id, but every time i got only the first one, i addedd code in foreach so it runs multiple times, but it gives me only one pdf.please someone help me.
public function pdf($ids){
$k = 0;
foreach ($ids as $key => $id) {
$data[$k]['academics'] = $this->Utility_model->get_all_from_table_where('member_academics', array('member_id' => $id));
$data[$k]['member_employment'] = $this->Utility_model->get_all_from_table_where('member_employment', array('member_id' => $id));
$data[$k]['member_data'] = $this->Utility_model->get_all_from_table_where('members',array('member_id' => $id));
$data[$k]['disclosure'] = $this->Utility_model->get_all_from_table('generalsettings',array('key'=>'disclosure'));
$data[$k]['enrollment_fee'] = $this->Utility_model->get_all_from_table('member_invoices',array('user_id' => $id,'paymentFor'=>'Enrollment Fee'));
$data[$k]['enrollment_fee']['payment'] = $this->Utility_model->get_all_from_table('member_payments',array('invoice_id'=>$data[$k]['enrollment_fee']['id']));
$j=0;
if (!empty($data[$k]['member_data'])) {
foreach ($data[$k]['member_data'] as $member) {
$data[$k]['member_data'][$j]['term'] = $this->Utility_model->get_all_from_table('term', array('term_id' => $member['term_id']));
$data[$k]['member_data'][$j]['degree'] = $this->Utility_model->get_all_from_table('degree', array('degree_id' => $member['degree_id']));
$data[$k]['member_data'][$j]['year'] = $this->Utility_model->get_all_from_table('year', array('year_id' => $member['year_id']));
$data[$k]['member_data'][$j]['address'] = $this->Utility_model->get_all_from_table('member_addresses', array('id' => $member['address_id']));
$j++;
}
}
$this->load->view('admin/reports_management/applications_pdf/pdf_output',$data[$k],false);
$html = $this->output->get_output();
$this->load->library('dompdf_gen');
$this->dompdf->load_html($html);
$this->dompdf->render();
$this->dompdf->stream($k."file".".pdf");
$k++;
}
// echo "<pre>";
// print_r($data);
// die;
}
As long as you only request the page once you cannot get the controller method to output more than one file. You could either try to instead make a multiple page PDF or you need to change how the controller is called, and call it multiple times.
See this answer for some input about making multiple page PDF: How to create several pages with dompdf

Resources