Hello i'm trying to use eloquent in my code:
$nr_riga = 0;
foreach($data_detail as $key => $row_detail) {
$nr_riga = $key + 1;
$new_orders_details->nr_riga = $nr_riga;
$new_orders_details->codice_articolo = $row_detail['codice_articolo'];
$new_orders_details->quantita = $row_detail['quantita'];
$new_orders_details->prezzo = $row_detail['prezzo'];
$new_orders_details->order_id = $new_orders_grid->id;
$new_orders_details->save();
// DB::table('orders_detail')->insert([
// 'order_id' => $new_orders_details->order_id,
// 'nr_riga' => $nr_riga,
// 'codice_articolo' => $new_orders_details->codice_articolo,
// 'quantita' => $new_orders_details->quantita,
// 'prezzo' => $new_orders_details->prezzo,
// ]);
}
This loop works both ways but not equally.. when i use $new_orders_details->save(); it inserts to the db a single row,seems to not looping.
DB::table('orders_detail')->insert does the job as i want.
How to convert it to eloquent for have same result?
This is the db screen:
You have to create new model instance in loop.
$new_orders_details = new OrderSDetail();
Since I cannot comment, can you try this solution?
$ordersDetail = new OrderSDetail();
$ordersDetail->insert([ //your data here]);
I think you can prepare date in loop and make one batch insert using Model::insert($your_data)
Saving in loop it is not best way to save data to db
Like:
$data = [];
foreach($data_detail as $key => $row_detail) {
$nr_riga = $key + 1;
$data[]['nr_riga'] = $nr_riga;
$data[]['codice_articolo'] = $row_detail['codice_articolo'];
$data[]['quantita'] = $row_detail['quantita'];
$data[]['prezzo'] = $row_detail['prezzo'];
$data[]['order_id'] = $new_orders_grid->id;
}
NewOrderDetails::insert($data);
It is save all you data with using model
Related
2 values are collected from the form as variables and rest as array. Then saving the values inside foreach loop in store method.
There is no problem with Array values, but for single variables, the values are showing null for the way I am trying.
I am trying to save $start and $end values inside the foreach loop. The code is below:
$start = $request->start;
$end = $request->end;
foreach ($request->user_id as $key => $val) {
$bill = new UserBill;
if (is_array($request->checked) && in_array($val, $request->checked)) {
$bill->start = $start;
$bill->end = $end;
$bill->amount = $request->amount[$key];
$bill->package = $request->package[$key];
$bill->package_type = $request->package_type[$key];
$bill->user_id = $val;
$bill->save();
}
}
Please help.
You can try sending the information directly to the save method instead populating an object.
foreach ($request->user_id as $key => $val) {
$bill = new UserBill;
if (is_array($request->checked) && in_array($val, $request->checked)) {
$bill->save([
"start" => $request->start,
"end" => $request->end,
"amount" => $request->amount[$key],
"package" => $request->package[$key],
"package_type" => $request->package_type[$key],
"user_id" => $val
]);
}
}
Just make sure all the variables has content. You can check by using the dd() helper
dd($request->toArray()); //toArray() for an easier looking on the output
check your variables are declared in your model in the fillable part https://laravel.com/docs/7.x/eloquent#mass-assignment , also try to put Log to see the values of your variables:
Log::info($start)
Log::info($end)
I am inserting data to the database using insert_batch() function.
I want to split the process.
I mean if I want to create 10,000 serial numbers. but 1,000 rows at a time, it should run the create process 10 times in a loop.
How can I do that?
$serial_numbers = $this->serial_numbers_model->generate_serial_numbers($product_id, $partner_id, $serial_number_quantity, $serial_number_start);
$issued_date = date("Y-m-d H:i:s");
$inserted_rows = 0;
foreach ($serial_numbers as $sn) {
$check_number = $this->serial_numbers_model->generate_check_number();
$first_serial_number = reset($serial_numbers);
$last_serial_number = end($serial_numbers);
$inserted_rows++;
$insert_data[] = array(
'partner_id' => $partner_id,
'product_id' => $product_id,
'check_number' => $check_number,
'serial_number' => $sn,
'issued_time' => $issued_date,
'serial_number_status' => CREATE_STATUS
);
}
$this->serial_numbers_model->insert_batch($insert_data);
}
Probably your serial_numbers_model->insert_batch() is just a wrapper around Codeigniter's native insert_batch()? The code below uses the native one for clarity, replace it with yours as required.
// Track how many in your batch, and prepare empty batch array
$count = 0;
$insert_data = [];
foreach ($serial_numbers as $sn) {
// ... your code, prepare your data, etc ...
$count++;
$insert_data[] = array(
// ... your data ...
);
// Do you have a batch of 1000 ready?
if ($count === 1000) {
// Yes - insert it
$this->db->insert_batch('table', $insert_data);
// $this->serial_numbers_model->insert_batch($insert_data);
// Reset the count, and empty the batch, ready to start again
$count = 0;
$insert_data = [];
}
}
// Watch out! If there were 1001 serial numbers, the first 1000 were handled,
// but the last one hasn't been inserted!
if (sizeof($insert_data)) {
$this->db->insert_batch('table', $insert_data);
}
I use CodeIgniter, and when an insert_batch does not fully work (number of items inserted different from the number of items given), I have to do the inserts again, using insert ignore to maximize the number that goes through the process without having errors for existing ones.
When I use this method, the kind of data I'm inserting does not need strict compliance between the number of items given, and the number put in the database. Maximize is the way.
What would be the correct way of a) using insert_batch as much as possible b) when it fails, using a workaround, while minimizing the number of unnecessary requests?
Thanks
The Correct way of inserting data using insert_batch is :
CI_Controller :
public function add_monthly_record()
{
$date = $this->input->post('date');
$due_date = $this->input->post('due_date');
$billing_date = $this->input->post('billing_date');
$total_area = $this->input->post('total_area');
$comp_id = $this->input->post('comp_id');
$unit_id = $this->input->post('unit_id');
$percent = $this->input->post('percent');
$unit_consumed = $this->input->post('unit_consumed');
$per_unit = $this->input->post('per_unit');
$actual_amount = $this->input->post('actual_amount');
$subsidies_from_itb = $this->input->post('subsidies_from_itb');
$subsidies = $this->input->post('subsidies');
$data = array();
foreach ($unit_id as $id => $name) {
$data[] = array(
'date' => $date,
'comp_id' => $comp_id,
'due_date' => $due_date,
'billing_date' => $billing_date,
'total_area' => $total_area,
'unit_id' => $unit_id[$id],
'percent' =>$percent[$id],
'unit_consumed' => $unit_consumed[$id],
'per_unit' => $per_unit[$id],
'actual_amount' => $actual_amount[$id],
'subsidies_from_itb' => $subsidies_from_itb[$id],
'subsidies' => $subsidies[$id],
);
};
$result = $this->Companies_records->add_monthly_record($data);
//return from model
$total_affected_rows = $result[1];
$first_insert_id = $result[0];
//using last id
if ($total_affected_rows) {
$count = $total_affected_rows - 1;
for ($x = 0; $x <= $count; $x++) {
$id = $first_insert_id + $x;
$invoice = 'EBR' . date('m') . '/' . date('y') . '/' . str_pad($id, 6, '0', STR_PAD_LEFT);
$field = array(
'invoice_no' => $invoice,
);
$this->Companies_records->add_monthly_record_update($field,$id);
}
}
echo json_encode($result);
}
CI_Model :
public function add_monthly_record($data)
{
$this->db->insert_batch('monthly_record', $data);
$first_insert_id = $this->db->insert_id();
$total_affected_rows = $this->db->affected_rows();
return [$first_insert_id, $total_affected_rows];
}
AS #q81 mentioned, you would split the batches (as you see fit or depending on system resources) like this:
$insert_batch = array();
$maximum_items = 100;
$i = 1;
while ($condition == true) {
// code to add data into $insert_batch
// ...
// insert the batch every n items
if ($i == $maximum_items) {
$this->db->insert_batch('table', $insert_batch); // insert the batch
$insert_batch = array(); // empty batch array
$i = 0;
}
$i++;
}
// the last $insert_batch
if ($insert_batch) {
$this->db->insert_batch('table', $insert_batch);
}
Edit:
while insert batch already splits the batches, the reason why you have "number of items inserted different from the number of items given" might be because the allowed memory size is reached. this happened to me too many times.
I am trying to insert/update +/- 10k rows with a foreach loop. The complete loop duration is about 3-5minutes. Are there any tips on my code to do the insertion of update faster? The $rows are retrieved from a xls file converted to domdocument.
foreach($rows as $key => $row)
{
if($key < 1){continue;}
$cells = $row -> getElementsByTagName('td');
foreach ($cells as $cell) {
$project_id = $cells[0]->nodeValue;
$title = $cells[1]->nodeValue;
$status = $cells[2]->nodeValue;
$projectmanager = $cells[3]->nodeValue;
$engineer = $cells[4]->nodeValue;
$coordinator = $cells[5]->nodeValue;
$contractor_a = $cells[6]->nodeValue;
$contractor_b = $cells[7]->nodeValue;
$gsu = $cells[9]->nodeValue;
$geu = $cells[10]->nodeValue;
$query = $this->Projects->find('all')->select(['project_id'])->where(['project_id' => $project_id]);
if ($query->isEmpty()) {
$project = $this->Projects->newEntity();
$project->title = $title;
$project->project_id = $project_id;
$project->status = $status;
$project->projectmanager = $projectmanager;
$project->engineer = $engineer;
$project->coordinator = $coordinator;
$project->contractor_a = $contractor_b;
$project->contractor_b = $contractor_a;
$project->gsu = date("Y-m-d H:i:s");
$project->geu = date("Y-m-d H:i:s");
$project->gsm = date("Y-m-d H:i:s");
$project->gem = date("Y-m-d H:i:s");
if ($this->Projects->save($project)) {
//$this->Flash->success(__('The project has been saved.'));
continue;
}else{
debug($project->errors());
}
}else{
continue;
$query->title = $title;
$query->status = $status;
$query->projectmanager = $projectmanager;
$query->engineer = $engineer;
$query->coordinator = $coordinator;
$query->contractor_a = $contractor_b;
$query->contractor_b = $contractor_a;
$query->gsu = $gsu;
$query->geu = $geu;
if ($this->Projects->save($query)) {
//$this->Flash->success(__('The project has been saved.'));
continue;
}
}
}
//$this->Flash->error(__('The project could not be saved. Please, try again.'));
}
For faster bulk inserts don't use entities but rather generate insert queries directly.
https://book.cakephp.org/3.0/en/orm/query-builder.html#inserting-data
Ello, my vriend.
The TableClass->save() method is useful when saving one single record, in your case, you should use TableClass->saveMany() instead.
For this to happen, you need to treat your entities as arrays inside your foreach.
After the foreach, you will use another method from the tableclass (newEntities) to convert the array into entities before finally save them.
Basic example:
//Lets supose our array after our foreach become something like this:
$all_records =
[
//Each item will be an array, not entities yet
[
'name' => 'I.N.R.I.',
'year' => '1987',
'label' => 'Cogumelo',
'country' => 'Brazil',
'band' => 'Sarcófago',
'line_up' => '[{"name":"Wagner Antichrist","role":"Vomits, Insults"},{"name":"Gerald Incubus","role":"Damned Bass"},{"name":"Z\u00e9der Butcher","role":"Rotten Guitars"},{"name":"D.D. Crazy","role":"Drums Trasher"}]'
],
//Another record coming in..
[
'name' => 'Eternal Devastation',
'year' => '1986',
'label' => 'Steamhammer',
'country' => 'Germany',
'band' => 'Destruction',
'line_up' => '[{"name":"Marcel Schmier","role":"Vocals, Bass"},{"name":"Mike Sifringer","role":"Guitars"},{"name":"Tommy Sandmann","role":"Drums"}]'
]
];
//Time to get the tableclass...
$albums = TableRegistry::get('Albums');
//Time to transform our array into Album Entities
$entities = $albums->newEntities($all_records);
//Now, we have transformed our array into entities on $entities, this is the variable we need to save
if(!$albums->saveMany($entities))
{
echo "FellsBadMan";
}
else
{
echo "FellsGoodMan";
}
You can read more about here
I'm trying to filter an array (derived from a json object), so as to return the array key based on the value. I'm not sure if array search $key = array_search($value, $array); is the best way to do this (I can't make it work), and I think there must be a better way.
So far I've got this, but it isn't working. Grateful for any help!
public function getBedroomData(array $data,$num_beds = null,$type) {
$data = (array) $data;
if($num_beds > 0) {
$searchstring = "avg_".$num_beds."bed_property_".$type."_monthly";
} else {
$searchstring = "avg_property_".$type."_monthly";
}
$avg_string = array_search($data, $searchstring);
return $avg_string;
}
The array consists of average property prices taken from the nestoria api as follows:
http://api.nestoria.co.uk/api?country=uk&pretty=1&action=metadata&place_name=Clapham&price_type=fixed&encoding=json
This returns a long json object. My problem is that the data isn't consistent - and I'm looking for the quickest (run time) way to do the following:
$data['response']['metadata']['0'] //= data to return, [0] unknown
$data['response']['metadata']['0']['metadata_name'] = "avg_1bed_property_rent_monthly" //= string I know!
$data['response']['metadata']['1'] //= data to return, [1] unknown
$data['response']['metadata']['1']['metadata_name'] = "avg_1bed_property_buy_monthly" //= string I know!
$data['response']['metadata']['2'] = //= data to return, [2] unknown
$data['response']['metadata']['2']['metadata_name'] = "avg_2bed_property_buy_monthly" //= string I know!
.....
.....
.....
$data['response']['metadata']['10'] = avg_property_rent_monthly
$data['response']['metadata']['11'] = avg_property_buy_monthly
$data['response']['metadata'][most_recent_month] = the month reference for getting the data from each metadata list..
It isn't possible to filter the initial search query by number of bedrooms as far as I can work out. So, I've just been array slicing the output to get the information I've needed if bedrooms are selected, but as the data isn't consistent this often fails.
To search inside that particular json response from nestoria, a simple foreach loop can be used. First off, of course call the json data that you need. Then, extract the whole data, the the next step if pretty straightforward. Consider this example:
$url = 'http://api.nestoria.co.uk/api?country=uk&pretty=1&action=metadata&place_name=Clapham&price_type=fixed&encoding=json';
$contents = file_get_contents($url);
$data = json_decode($contents, true);
$metadata = $data['response']['metadata'];
// dummy values
$num_beds = 1; // null or 0 or greater than 0
$type = 'buy'; // buy or rent
function getBedroomData($metadata, $num_beds = null, $type) {
$data = array();
$searchstring = (!$num_beds) ? "avg_property_".$type."_monthly" : "avg_".$num_beds."bed_property_".$type."_monthly";
$data['metadata_name'] = $searchstring;
$data['data'] = null;
foreach($metadata as $key => $value) {
if($value['metadata_name'] == $searchstring) {
$raw_data = $value['data']; // main data
// average price and data points
$avg_price = 0;
$data_points = 0;
foreach($raw_data as $index => $element) {
$avg_price += $element['avg_price'];
$data_points += $element['datapoints'];
}
$data_count = count($raw_data);
$price_average = $avg_price / $data_count;
$data_points_average = $data_points / $data_count;
$data['data'][] = array(
'average_price' => $price_average,
'average_datapoints' => $data_points_average,
'data' => $raw_data,
);
}
}
return $data;
}
$final = getBedroomData($metadata, $num_beds, $type);
print_r($final);