MySql Update Query to insert JSON values - mysql

In MySql I have two tables: staff and certifications. There is a one-to-many relationship where staff.pk = certifications.fk.
For each staff member, I need to insert their multiple certifications.name values into a JSON column in the staff table.
I also need to be able to read this as an array cast in a Laravel - does that mean it needs to be a JSON array, rather than a JSON object?
UPDATE:
I need to do this as a batch process, since I have many thousands of records to process. That's why I am concencentrating on the raw SQL. Instantiating Eloquent models would not work from a performance perspective.

you can use Accessors & Mutators
namespace App;
use Illuminate\Database\Eloquent\Model;
class Staff extends Model
{
//assuming you have certificates column in staff table to store json data
public function setCertificatesAttribute($certificates)
{
$this->attributes['certificates'] = json_encode($certificates);
}
public function getCertificatesAttribute()
{
if($certificates != null){
return json_decode($certificates, true); //force to array
}
return []; //default empty array
}
}
Now if you create or update staff
Staff::create([
'name' => 'Staff1',
'certificates' => ['certificate1', 'certificate2']
]);
Then it will automatically saved as a json data in your staff table. And when you fetch data using $staff->certificates then it will return you array.
hope it may solve your problem

Related

Optimization of Laravel pivot table relationship

I have a pivot table called invite_riskarea which is designed as follows:
This table handles the permissions that have a specific user (through an invite id) to access to specific riskfields. Each riskfield is associated with a riskarea which acts as the main container of specific riskfields.
Within the model Invite I have this relationship:
public function riskareas()
{
return $this->belongsToMany(Riskarea::class)->withPivot('riskfield_id', 'insert', 'edit', 'view');
}
In this way I can return all the riskareas associated with a specific invite, and I should be able to return all the riskfields associated with a specific riskarea in the same invite model.
As you can see from the table invite_riskarea, I have three columns called insert, edit, and delete. These columns manage the types of permissions assigned to a specific user (via an invite id) for a specific riskfield belonging to a riskarea.
I'm trying to retrieve the riskarea permission in the following way:
$invite = Invite::where('id', 58)->first();
$riskarea = $invite->riskareas[0];
$riskfield = $riskareas->riskfields[0];
echo 'view permission => ' . $riskfield->insert;
The problem's that I'm not able to setup a correct relationship in the Invite model that returns me the pivot data of the permissions columns only for the riskfield associated with the riskarea.
So I have manage to handle this situation in this way:
$riskareas = Riskarea::all();
foreach ($riskareas as &$riskarea) {
foreach ($riskarea->riskfields as &$riskfield) {
$result = DB::table('invite_riskarea')
->select('insert', 'edit', 'view')
->where([
'riskarea_id' => $riskarea->id,
'riskfield_id' => $riskfield->id
])
->first();
if ($result) {
$riskfield->insert = $result->insert;
$riskfield->edit = $result->edit;
$riskfield->view = $result->view;
}
}
}
Essentially, I get all the riskareas, and then I iterate over the riskfields associated. For each riskfield, I get the permissions in the invite_riskarea table and then I have the correct structure that I want.
So to summarize:
Is it actually possible create a model relationship that returns the permissions for riskfield and not for riskarea?
Is my table implementation good enough to handle that situation?
I suggest you define back the many-to-many relation for the Riskfield model with the Invite model.
You can also define a direct many-to-many relationship with riskfield in the Invite model. This is how convenient it is for you personally.
And so the inverse many-to-many relationship
public function invites()
{
return $this->belongsToMany(Invite::class)->withPivot('insert', 'edit', 'view');
}
Then get all objects' Riskfields that are associated with the specified invite:
$riskfields = Riskfields::wherehas('invites' . function (Builder $query) use ($invite_id) {
$query->where('invites.id', $invite_id);
})->with('invites')->get();
Then you can access the desired fields of the pivot table in the specified way:
foreach ($riskfields as $riskfield) {
foreach ($riskfield->invites as $invite) {
$insertRiskField = $invite->pivot->insert;
$editRiskField = $invite->pivot->edit;
$viewRiskField = $invite->pivot->view;
}
}
Eager loading executes one query to the database
Yes
Documentation Laravel

how to name database column appropriately

In excel file, I have columns like this; 11.01-12.00, 12.01-13.00, ..., 29.01-30.00. And the content of the column is the price. I want to store a price in many ranges in MySQL like excel column.
Do I have to create a table like this or Do your guys have any better way please guide me?
An option may be to define a column price_range or prices as json column and store the data as key=>value pairs for eg: '11.01-12:00'=> 11.50
In your migration file for the table, add a column
$table->json('prices');
And in your model class, specify to cast prices column as array.
class MyModel extends Model
{
protected $casts = ['prices' => 'array'];
//... rest of the class code
}
By specifying the cast, you can now use associative array to store data on the column, you can work in php arrays to store and update data.
$myModel = new MyModel;
$myModel->prices = [
'11.01-12.00' => 11.50,
'12.01-13.00' => 12.35,
//...
'29.01-30.00' => 29.82,
];
$myModel->save();
To update data
$myModel = MyModel::find(5);
$newPrices = [
'11.01-12.00' => 11.20,
'12.01-13.00' => 12.63,
//...
'29.01-30.00' => 29.05,
]
$myModel->update(['prices' => $newPrices]);
/OR to update price for a specific price range
$myModel->update(['prices->11.01-12.00' => 11.25]);
Laravel docs:
https://laravel.com/docs/8.x/eloquent-mutators#array-and-json-casting
https://laravel.com/docs/8.x/eloquent#mass-assignment-json-columns
https://laravel.com/docs/8.x/queries#updating-json-columns
In your database table migration file, define a column called price to hold your value.
$table->integer('price');
Store your price as the lowest denominator for your currency performing whatever arithmetic is required to perform the conversions in/out of the database.
There is no need for you to create individual columns for different prices.
Edit 1
Based on your question update that the information is in an excel file, you'll want to make use of a package such as Laravel Excel (no point reinventing the wheel) to perform your import.
Nice tutorial for importing an excel file here

Expanding this method to write to the database

Hi I followed a tutorial to implement a friend system. It all works find, but I need to post other columns to the row that just the id's. How would I expand that.
This is the method that is accessed when the add friend button is clicked
public function getAdd($id){
$user = User::where('id', $id)->first();
//After passing all checks. Add other account
Auth::user()->addFriend($user);
echo "Sent";
}
AddTenancy Method
public function addFriend(User $user){
$this->friendsOf()->attach($user->id);
}
I assume the relationship is many-to-many between users. And you need to add additional data to the pivot.
Here's how you'd do that:
public function addFriend(User $user){
$this->friendsOf()->attach($user->id, ['another_col' => 'some data']);
}
Replace 'another_col' and some data with your column and your data. You can also add more than 1 column into the array.

Relationships between tables in laravel using backpack package

I am using backpack CRUD package to create my website project in laravel 5.2
I want to establish a relationship between two tables. First table is called customer and second table is called transaction. Each customer has many transaction(1:N relationship).
Customer table record:
ID Name
123456 xyz
Transaction table record:
ID CustomerID
101010 123456
I know that I have to specify the relation in the customer model. But, how can I display the result of the relationship in CRUD ?
You should have relationships on both the Transaction and the Customer models, so you can do $customer->transactions and $transaction->customer:
class Customer extends Model
{
/**
* Get the comments for the blog post.
*/
public function transactions()
{
return $this->hasMany('App\Transactions', 'CustomerID', 'ID');
}
}
and
class Transaction extends Model
{
/**
* Get the comments for the blog post.
*/
public function customer()
{
return $this->belongsTo('App\Customer', 'CustomerID', 'ID');
}
}
Spend some time in the Eloquent Relationships Documentation. It's really important to understand them if you want to be a Laravel developer.
In order to display the relationship in the CRUD, you can then use Backpack's select column type to display it in the table view and select or select2 field types to display it in the add/edit views. Read the CRUD Example Entity to better understand how that works.
First of all when you are creating migrations for both tables, table which contain Foreign Key (FK) must have field like this:
public function up(){
$table->increments('id');
$table->integer('customerID')->unsigned();
}
After that you are need to call next command into console
php artisan migrate
Next is going next commands:
php arisan backpack:crud customers
php arisan backpack:crud transactions
After that you need to define functions in models which returns values from other tables. Customer models need to have next function
public function transactions(){
return $this->hasMany('Transaction');
}
Transaction model must have next function
public function customer() {
return $this->belongsTo('Customer');
}
Next you must add CRUD field in Customer controller to display
transactions in select box.
$this->crud->addField([
'label' => 'Transactions', // Label for HTML form field
'type' => 'select2', // HTML element which displaying transactions
'name' => 'customerID', // Table column which is FK for Customer table
'entity'=> 'customer', // Function (method) in Customer model which return transactions
'attribute' => 'ID', // Column which user see in select box
'model' => 'Transaction' // Model which contain FK
]);
Hope this helps :)
After you built onetomany relationship with transaction, you can get the results.
$customer=Customer::where(['id'=>'123456'])->with('transaction')
->first();
print_r($customer->Name); // gives the customer name
foreach($customer->transaction as $cid)
{
print_r($cid->CustomerID); // gives the customer id
}
Laravel Relationships Documentation is always helpful. Go through it.

laravel5-How can i hide the specific column of withPivot?

I use belongstomany function to get the models and used withPivot() to get an extra column data in the pivot table. However, the withPivot() function will add the 2 foreign keys in the output json. I want to hide thses keys and only show the column I want to display.
The follwing is my response data
{"status_code":"1","next_page":"2","dataset":[{"id":"829","req_start_time":"2016-03-13 14:55:00","req_end_time":"2016-03-13 09:55:00","content":[{"name":"\u9752\u6912\u7092\u725b\u8089","price":"120","pic_url":"","detail":"\u8d85\u7ea7\u597d\u5403\u7684\u54df","pivot":{"waiter_request_id":"829","goods_id":"2","count":"2"}}
as you see the pivot json object contains two id keys.
how could i remove them from the object? or some other ways to solve this get the right way of this need?
thx in advance!
Now the question already upgraded!
How can I add this 'count' parameter of pivot in the object which belongs to 'content'
Finally,I figured out the right way to solve this problem. Follwing the code:
class Goods extends Model{
......
......
public function newPivot(Model $parent, array $attributes, $table, $exists)
{
$pivot = new Pivot($parent, $attributes, $table, $exists);
$pivot->addHidden(
array(
'waiter_request_id',
'goods_id'
)
);
return $pivot;
}
}
you can rewrite this method to provide a new pivot object to the Model in your 'belongsToMany'