Laravel UpdateOrCreate To Be Different values on Create on Update - php

Is there something like UpdateOrCreate I can use to have different values on create and on update. Meaning if it’s updating i don’t want it to change a certain column but i want it to insert the first time.
eg
$person = ['name'=> 'John', 'age' => 6, 'joined' => '2017-01-01'];
If John exists update age. If it doesn’t insert age and joined;
People::updateOrCreate(
['name' => $person['name']],
['age' => $person['age'], 'joined' => $person['joined']]
)
will update joined every time and i don't wanna change it.

You can use updateOrNew which doesn't persist it to the database and then check if it is not already in the database you can change the property you want to change.
$record = People::updateOrNew(
['name' => $person['name']],
['age' => $person['age']]
);
if(!$record->exists()) {
$record->joined = $person['joined'];
}
$record->save();
But if you are only trying to get the record if it exists and create it if it doesn't, use firstOrCreate() instead. That won't affect existing records, only return them, and it will create the record if it doesn't exist.

There is no any other option else you can try following:
$person = People::where('name', $name)->first();
if (!is_null($person)) {
$person->update([
'age' => $age
]);
}else{
$person = People::create([
'name' => $name,
'age' => $age,
'joined' => date('Y-m-d')
]);
}

Related

How to merge exists data with new data?

Method 1 : Here I wrote the code for insert booking seat data into the database
Problem : When I book new seat it will creating new row so I'm getting duplicate rows so I tried method 2
Method 1 code :
$booking = new Bookings();
$booking->users_id = 4;
$booking->schedules_id = $schedules_id;
$booking->buses_id = $buses_id;
$booking->routes_id = $routes_id;
$booking->seat = implode(',', $seat);
$booking->price = $request->price;
$booking->profile = 'pending';
Method 2 : Here checking schedules_id equal to exists schedules_id then update seat and other data's
Problem : Insert new data updating old data
Method 2 code :
$booking = Bookings::updateOrCreate(
['schedules_id' => $schedules_id], // match the row based on this array
[ // update this columns
'buses_id' => $buses_id,
'routes_id' => $routes_id,
'seat' => json_encode($seat),
'price' => $request->price,
'profile' => 'pending',
]
);
// I don't know this is logically correct or wrong
My idea : Here I'm retrieving old data and storing into one variable then merging old data and new data into one column
Problem : Getting error.
My idea code :
$extSeat = DB::table('bookings')->select('seat')->get();
$booking = Bookings::updateOrCreate(
['schedules_id' => $schedules_id],
[ // update this columns
'buses_id' => $buses_id,
'routes_id' => $routes_id,
'seat' => implode(",", array_merge($seat,$extSeat)),
'price' => $request->price,
'profile' => 'pending',
]);
what i actually need ? : i need merge exists data with new data without updating.
Old data look like A1,B1
when insert new data like C1
i need data like this A1,B1,C1
I hope I explain clear enough. Any help is appreciated, thank you.
I don't know this is a correct logic or not but works for me, any other suggestions are welcome.
$extSeat = DB::table('bookings')->select('seat')->first();
$extSeat = explode(",", $extSeat->seat);
$booking = Bookings::updateOrCreate(
['schedules_id' => $schedules_id],
[ // update this columns
'buses_id' => $buses_id,
'routes_id' => $routes_id,
'seat' => implode(",", array_merge($seat,$extSeat )),
'price' => $request->price,
'profile' => 'pending',
]);

Save all record records using request->all in Laravel

Laravel provides a great help for developers to save all input fields of a form which is one record with one line of code.
like if I want to save a form which has multiple input fields and one record to database like:
then I can save it with below code and it works great:
SaveOrder:: create($request->all());
Now I have a question. If I have multiple records (multiple rows) in a form and I can add new rows with a button pressed. Then how can I save all records with above code?
Like:
It's easy to do that using Eloquent :
$data = array(
array('field1'=>'value1', 'field2'=> value2),
array('field1'=>'value1', 'field2'=> value1),
//...
);
Model::insert($data);
Assuming your input names look something like name[], since you can add rows on the fly, you can retrieve the input as an array, and insert them using something like this:
$data = [];
$names = request('name');
$product_names = request('product_name');
$product_colour = request('product_colour');
$product_size = request('product_size');
for ($i = 0; $i < count($names); $i++) {
// Add checks to make sure indices actually exist, probably using preprocessing in JS
$data[] = [
'name' => $names[$i],
'product_name' => $product_names[$i],
'product_colour' => $product_colour[$i],
'product_size' => $product_size[$i],
];
}
Model::insert($data);
The best answer for this question is using foreach statement. Like:
$CustomerName= $request -> input('CustomerName');
$ProductId= $request -> input('ProductId');
$ProductName= $request -> input('ProductName');
$ProductColor= $request -> input('ProductColor');
foreach( $ProductId as $key => $n ) {
SaveOrder::insert(
array(
'CustomerName' => $CustomerName[$key],
'ProductId' => $ProductId[$key],
'ProductName' => $ProductPrice[$key],
'ProductColor' => $ProductQuantity[$key],
)
);}
Use upsert
If you use Laravel 8 or above, you can make use of upsert. Such an useful function to insert or update matching records at the same time.
SaveOrder::upsert($request->all(), ['id'], ['CustomerName', 'ProductName', 'ProductColor', 'ProductID']);
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:
Flight::upsert([
['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99],
['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
], ['departure', 'destination'], ['price']);
Read the documentation on Laravel Upsert

How to get multiple auto incremented id in laravel database [duplicate]

I am inserting multiple rows at the same time, say 2 rows
$multiple_rows = [
['email' => 'taylor#example.com', 'votes' => 0],
['email' => 'dayle#example.com', 'votes' => 0]
];
DB::table('users')->insert($multiple_rows);
How can I get those inserted ids.
I am doing it, this way for now.
foreach($multiple_rows as $row){
DB::table('users')->insert($row);
$record_ids[] = DB::getPdo()->lastInsertId();
}
Any other good way to do it, without inserting single row each time.
You could do something like the following:
$latestUser = DB::table('users')->select('id')->orderBy('id', 'DESC')->first();
$multiple_rows = [
['email' => 'taylor#example.com', 'votes' => 0],
['email' => 'dayle#example.com', 'votes' => 0]
];
DB::table('users')->insert($multiple_rows);
$users = DB::table('users')->select('id')->where('id', '>', $latestUser->id)->get();
If you really need all the inserted ID's
$dataArray = [
['name' => 'ABC'],
['name' => 'DEF']
];
$ids = [];
foreach($dataArray as $data)
{
$ids[] = DB::table('posts')->insertGetId($data);
}
To get all id with a massive insertion I think the good way is to first get the last id in the table, make the massive insertion and get the last id. In theory they must follow, unless there has been an insertion from another connection. To avoid that the solution is a transaction.
Update
Also read the documentation

How can i update or insert compare two fields from database

I want to compare either mobile or email fields exists in database it should update row else insert row
$ref = Ref::updateOrCreate(
[
'mobile' => $request['mobile'],
'email' => $request['email_address']
],
[
'firstname' => $request['firstname'],
"lastname" => $request['lastname'],
"mobile" => $request['mobile'],
"email" => $request['email_address'],
"mobile_verified" => $req->session()->get('mobile_verified'),
"quiz_data" => $req->session()->get('quiz_data'),
"verification_token" => $req_token
]
);
Do like this
$result= DB::statement("INSERT INTO table_name
(firstname,lastname,mobile,email,mobile_verified,quiz_data,verification_token)
VALUES ('".$request['firstname']."','".$request['lastname']."','".$request['mobile']."','"
.$request['email_address']."','".$req->session()->get('mobile_verified')."','"
.$req->session()->get('quiz_data')."','".$req_token."',)
ON DUPLICATE KEY UPDATE mobile = VALUES(mobile),email = VALUES(email);");
Replace table_name with your table name and try .
Here your mobile and email will be updated if the data is present before.
There is no Laravel function to compare on either field, you will have to execute two queries manually.
// Find an existing Ref
$ref = Ref::where('mobile', $request['mobile'])
->orWhere('email', $request['email_address'])
->first();
// Test if exists
if (isset($ref))
{
$ref->update([
// Update fields
]);
}
else
{
$ref = Ref::create([
// Create fields
]);
}

Reference Relationship ID on CSV import

I have 2 models that I want to populate by a CVS import. The first model is a list of Retail Stores and the second model is the Retail Stores corresponding locations.
This is the CSV import:
name,email,website,street_number,street_address,city,country,postcode,latitude,longitude
"Example name",info#example.com,10,"random street",amsterdam,netherlands,4000,52.666,4.3333
The RetailStores.php model will need these values:
name,
email,
website
The LocationStores.php model will need these values:
street_number,
street_address,
city,
country,
postcode,
latitude,
longitude
I will extract the data from the CSV file inside a foreach loop and attaching them to an empty array variable, from here will use some Eloquent to populate the database. Below is how I do this:
$file = Input::file('csv_file');
$data = $this->retailer->processCsv($file);
$retailers = [];
$locations = [];
foreach ($data as $value) {
$retailers[] = array(
'user_id' => Auth::user()->id,
'name' => $value['name'],
'email' => $value['email'],
'website' => $value['website'],
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
);
$locations[] = array(
'retailer_id' => $value['retailer_id'], // ISSUE HERE
'street_number' => $value['street_number'],
'street_address' => $value['street_address'],
'city' => $value['city'],
'state' => $value['state'],
'country' => $value['country'],
'country_code' => $value['country_code'],
'postcode' => $value['postcode'],
'latitude' => $value['latitude'],
'longitude' => $value['longitude'],
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
);
Retailer::insert($retailers);
Location::insert($locations);
}
As noted above I have 2 separate models the Retailers and Locations. I need to reference the Retailer ID in the $locations array. For now I have one option which is to have users enter the relevant retailer store id for each location in the CSV file, but people are well.... you know.
However considering that the CSV file will supply a "Store Name" for each location it has, is there not a way to reference an increment ID for each unique store name within the array? for example if the CSV table had these values:
Fruit,info#fruit.com,www.fruit.com,1,"apple street",etc
Fruit,info#fruit.com,www.fruit.com,120,"pear parkway",etc
Fruit,info#fruit.com,www.fruit.com,350,"orange avenue",etc
Meat,info#meat.com,www.meat.com,33,"Steak street",etc
Meat,info#meat.com,www.meat.com,33,"Chicken Road",etc
When getting these values within the foreach loop, is there a way one could give an increment ID for each of the repeated Store names which would thus reference the relevant store to its location?
Any advice, greatly appreciated.
You could store the retailer name in a way where it's easy to check if a particular name is in the retailer array already, and grab the ID out if it is. Something like this:
foreach ($data as $value) {
$retailer_name = $value['name']; // for clarity
// is the retailer name in the retailers array already?
if (isset($retailers[$retailer_name])){
// get the ID
$retailer_id = $retailers[$retailer_name]['user_id'];
} else { // otherwise add a new one
$retailer_id = Auth::user()->id; //store the ID for use in Locations
// use retailer name for the key of the array, so it's easily findable later
$retailers[$retailer_name] = array(
'user_id' => $retailer_id,
'name' => $value['name'],
'email' => $value['email'],
'website' => $value['website'],
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
);
}
$locations[] = array(
'retailer_id' => $retailer_id, // add either the new or existing ID
'street_number' => $value['street_number'],
'street_address' => $value['street_address'],
'city' => $value['city'],
'state' => $value['state'],
'country' => $value['country'],
'country_code' => $value['country_code'],
'postcode' => $value['postcode'],
'latitude' => $value['latitude'],
'longitude' => $value['longitude'],
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
);
Retailer::insert($retailers);
Location::insert($locations);
}
You then have an array with strings as keys for $retailers, though, and if that's a problem for insertion, you'll have to make a separate array for retailers or change it to numeric keys before you insert.

Categories