MySQLでJSONを操作する方法
序章
MySQLバージョン5.7.8では、JSONドキュメントのデータにアクセスできるJSONデータ型が導入されています。
SQLデータベースは、設計が厳格になる傾向があります。 その性質上、構造化照会言語はデータ型とサイズの制約を適用します。
それに比べて、NoSQLデータベースは設計の柔軟性を促進します。 これらのスキーマのないデータベースでは、構造上の制限はなく、データのみが保存されます。
MySQLのJSONデータ型は、これら両方のシステムの長所を提供します。 これにより、データベースの一部を構造化し、他の部分を柔軟に保つことができます。
この記事の前半では、JSONフィールドを使用してデータベースを設計します。 MySQLで使用可能な組み込み関数を使用して、行を作成、読み取り、更新、および削除する手順を説明します。
この記事の後半では、EloquentORMとLaravelを利用してデータベースと通信します。 製品の表示、新しい製品の追加、既存の製品の変更、および製品の削除をサポートする管理パネルを作成します。
前提条件
この記事をフォローしたい場合は、次のものが必要になります。
- MySQL5.7.8以降およびPHP7.3.24以降。 Linux、Apache、MySQL、およびPHPのインストールに関するチュートリアルを参照できます
- SQLクエリにある程度精通している。
- PHPの記述にある程度精通している。
- Laravelにある程度精通している。
- このチュートリアルでは、Composerを介したLaravelのインストールを念頭に置いています。 Composerのインストールに関するチュートリアルを参照できます。
注: Laravelは、MySQL、PHP、およびComposerで環境を構成するDockerと連携するSailと呼ばれるツールを提供するようになりました。
ローカル環境のセットアップに問題がある場合、これは代替オプションになる可能性があります。
このチュートリアルは、MySQL v8.0.23、PHP v7.3.24、Composer v2.0.9、およびLaravelv8.26.1で検証されました。
ステップ1—スキーマの定義
このチュートリアルでは、さまざまな電子機器を販売するオンラインストアの在庫を定義するスキーマから構築します。
従来、エンティティ-属性-値モデル(EAV)パターンは、顧客が製品の機能を比較できるようにするために使用されていました。
ただし、JSONデータ型を使用すると、このユースケースへのアプローチが異なる場合があります。
データベースには名前が付けられます e_store
と名前の3つのテーブルがあります brands
, categories
、 と products
それぞれ。
を作成します e_store
データベース:
CREATE DATABASE IF NOT EXISTS `e_store`
DEFAULT CHARACTER SET utf8
DEFAULT COLLATE utf8_general_ci;
SET default_storage_engine = INNODB;
The brands
と categories
テーブルにはそれぞれがあります id
と name
分野。
を作成します brands
テーブル:
CREATE TABLE `e_store`.`brands`(
`id` INT UNSIGNED NOT NULL auto_increment ,
`name` VARCHAR(250) NOT NULL ,
PRIMARY KEY(`id`)
);
を作成します categories
テーブル:
CREATE TABLE `e_store`.`categories`(
`id` INT UNSIGNED NOT NULL auto_increment ,
`name` VARCHAR(250) NOT NULL ,
PRIMARY KEY(`id`)
);
次に、サンプルを追加します brands
:
INSERT INTO `e_store`.`brands`(`name`)
VALUES
('Samsung');
INSERT INTO `e_store`.`brands`(`name`)
VALUES
('Nokia');
INSERT INTO `e_store`.`brands`(`name`)
VALUES
('Canon');
次に、いくつか追加します categories
:
INSERT INTO `e_store`.`categories`(`name`)
VALUES
('Television');
INSERT INTO `e_store`.`categories`(`name`)
VALUES
('Mobile Phone');
INSERT INTO `e_store`.`categories`(`name`)
VALUES
('Camera');
次に、 products
テーブルと id
, name
, brand_id
, category_id
、 と attributes
田畑:
CREATE TABLE `e_store`.`products`(
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(250) NOT NULL ,
`brand_id` INT UNSIGNED NOT NULL ,
`category_id` INT UNSIGNED NOT NULL ,
`attributes` JSON NOT NULL ,
PRIMARY KEY(`id`) ,
INDEX `CATEGORY_ID`(`category_id` ASC) ,
INDEX `BRAND_ID`(`brand_id` ASC) ,
CONSTRAINT `brand_id` FOREIGN KEY(`brand_id`) REFERENCES `e_store`.`brands`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE ,
CONSTRAINT `category_id` FOREIGN KEY(`category_id`) REFERENCES `e_store`.`categories`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE
);
このテーブル定義は、外部キー制約を指定します brand_id
と category_id
フィールド、それらが参照することを指定する brands
と categories
それぞれテーブル。 このテーブル定義は、参照される行の削除を許可しないように指定し、更新された場合、変更は参照にも反映される必要があります。
The attributes
フィールドの列タイプは、MySQLで現在使用可能なネイティブデータ型であるJSONであると宣言されています。 これにより、MySQLでさまざまなJSON関連の構成を使用できます。 attributes
分野。
作成したデータベースの実体関連図は次のとおりです。
このデータベース設計は、効率と精度の点で最高ではありません。 考慮されていない一般的な実際のユースケースがいくつかあります。 たとえば、価格の列はありません products
テーブルであり、複数のカテゴリに属する製品のサポートはありません。 ただし、このチュートリアルの目的は、データベースの設計を教えることではなく、MySQLのJSON機能を使用して単一のテーブルでさまざまな性質のオブジェクトをモデル化する方法を教えることです。
ステップ2—JSONフィールドにデータを作成する
次に、を使用してデータベースに追加する製品を作成します。 INSERT INTO
と VALUES
.
次に、文字列化されたJSONオブジェクトを使用した、画面サイズ、解像度、ポート、スピーカーに関するデータを備えたテレビの例をいくつか示します。
INSERT INTO `e_store`.`products`(
`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Prime' ,
'1' ,
'1' ,
'{"screen": "50 inch", "resolution": "2048 x 1152 pixels", "ports": {"hdmi": 1, "usb": 3}, "speakers": {"left": "10 watt", "right": "10 watt"}}'
);
INSERT INTO `e_store`.`products`(
`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Octoview' ,
'1' ,
'1' ,
'{"screen": "40 inch", "resolution": "1920 x 1080 pixels", "ports": {"hdmi": 1, "usb": 2}, "speakers": {"left": "10 watt", "right": "10 watt"}}'
);
INSERT INTO `e_store`.`products`(
`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Dreamer' ,
'1' ,
'1' ,
'{"screen": "30 inch", "resolution": "1600 x 900 pixles", "ports": {"hdmi": 1, "usb": 1}, "speakers": {"left": "10 watt", "right": "10 watt"}}'
);
INSERT INTO `e_store`.`products`(
`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Bravia' ,
'1' ,
'1' ,
'{"screen": "25 inch", "resolution": "1366 x 768 pixels", "ports": {"hdmi": 1, "usb": 0}, "speakers": {"left": "5 watt", "right": "5 watt"}}'
);
INSERT INTO `e_store`.`products`(
`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Proton' ,
'1' ,
'1' ,
'{"screen": "20 inch", "resolution": "1280 x 720 pixels", "ports": {"hdmi": 0, "usb": 0}, "speakers": {"left": "5 watt", "right": "5 watt"}}'
);
この例では、5つの異なるテレビ製品を宣言しています。
または、組み込みのを使用することもできます JSON_OBJECT
JSONオブジェクトを作成する関数。
The JSON_OBJECT
関数は、次の形式のキーと値のペアのリストを受け入れます JSON_OBJECT(key1, value1, key2, value2, ... key(n), value(n))
JSONオブジェクトを返します。
これは、を使用した携帯電話の例です。 JSON_OBJECT
関数:
INSERT INTO `e_store`.`products`(
`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Desire' ,
'2' ,
'2' ,
JSON_OBJECT(
"network" ,
JSON_ARRAY("GSM" , "CDMA" , "HSPA" , "EVDO") ,
"body" ,
"5.11 x 2.59 x 0.46 inches" ,
"weight" ,
"143 grams" ,
"sim" ,
"Micro-SIM" ,
"display" ,
"4.5 inches" ,
"resolution" ,
"720 x 1280 pixels" ,
"os" ,
"Android Jellybean v4.3"
)
);
INSERT INTO `e_store`.`products`(
`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Passion' ,
'2' ,
'2' ,
JSON_OBJECT(
"network" ,
JSON_ARRAY("GSM" , "CDMA" , "HSPA") ,
"body" ,
"6.11 x 3.59 x 0.46 inches" ,
"weight" ,
"145 grams" ,
"sim" ,
"Micro-SIM" ,
"display" ,
"4.5 inches" ,
"resolution" ,
"720 x 1280 pixels" ,
"os" ,
"Android Jellybean v4.3"
)
);
INSERT INTO `e_store`.`products`(
`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Emotion' ,
'2' ,
'2' ,
JSON_OBJECT(
"network" ,
JSON_ARRAY("GSM" , "CDMA" , "EVDO") ,
"body" ,
"5.50 x 2.50 x 0.50 inches" ,
"weight" ,
"125 grams" ,
"sim" ,
"Micro-SIM" ,
"display" ,
"5.00 inches" ,
"resolution" ,
"720 x 1280 pixels" ,
"os" ,
"Android KitKat v4.3"
)
);
INSERT INTO `e_store`.`products`(
`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Sensation' ,
'2' ,
'2' ,
JSON_OBJECT(
"network" ,
JSON_ARRAY("GSM" , "HSPA" , "EVDO") ,
"body" ,
"4.00 x 2.00 x 0.75 inches" ,
"weight" ,
"150 grams" ,
"sim" ,
"Micro-SIM" ,
"display" ,
"3.5 inches" ,
"resolution" ,
"720 x 1280 pixels" ,
"os" ,
"Android Lollipop v4.3"
)
);
INSERT INTO `e_store`.`products`(
`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Joy' ,
'2' ,
'2' ,
JSON_OBJECT(
"network" ,
JSON_ARRAY("CDMA" , "HSPA" , "EVDO") ,
"body" ,
"7.00 x 3.50 x 0.25 inches" ,
"weight" ,
"250 grams" ,
"sim" ,
"Micro-SIM" ,
"display" ,
"6.5 inches" ,
"resolution" ,
"1920 x 1080 pixels" ,
"os" ,
"Android Marshmallow v4.3"
)
);
この例では、5つの異なる携帯電話製品を宣言しています。
それはまた利用しました JSON_ARRAY
値のセットが渡されたときにJSON配列を返す関数。
1つのキーを複数回指定すると、最初のキーと値のペアのみが保持されます。 これは、MySQLの用語でJSONの正規化と呼ばれます。 また、正規化の一環として、オブジェクトキーが並べ替えられ、キーと値のペア間の余分な空白が削除されます。
さらに、組み込みを使用することができます JSON_MERGE_PRESERVE
また JSON_MERGE_PATCH
JSONオブジェクトを作成する関数。
注:以前のバージョンのMySQLでは、 JSON_MERGE
、ただし、この関数は非推奨になりました。
'JSON_MERGE' is deprecated and will be removed in a future release. Please use JSON_MERGE_PRESERVE/JSON_MERGE_PATCH instead
このチュートリアルでは、 JSON_MERGE_PRESERVE
関数。 この関数は複数のJSONオブジェクトを受け取り、単一の集約オブジェクトを生成します。
これは、を使用したカメラの例です。 JSON_MERGE_PRESERVE
関数:
INSERT INTO `e_store`.`products`(
`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Explorer' ,
'3' ,
'3' ,
JSON_MERGE_PRESERVE(
'{"sensor_type": "CMOS"}' ,
'{"processor": "Digic DV III"}' ,
'{"scanning_system": "progressive"}' ,
'{"mount_type": "PL"}' ,
'{"monitor_type": "LCD"}'
)
);
INSERT INTO `e_store`.`products`(
`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Runner' ,
'3' ,
'3' ,
JSON_MERGE_PRESERVE(
JSON_OBJECT("sensor_type" , "CMOS") ,
JSON_OBJECT("processor" , "Digic DV II") ,
JSON_OBJECT("scanning_system" , "progressive") ,
JSON_OBJECT("mount_type" , "PL") ,
JSON_OBJECT("monitor_type" , "LED")
)
);
INSERT INTO `e_store`.`products`(
`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Traveler' ,
'3' ,
'3' ,
JSON_MERGE_PRESERVE(
JSON_OBJECT("sensor_type" , "CMOS") ,
'{"processor": "Digic DV II"}' ,
'{"scanning_system": "progressive"}' ,
'{"mount_type": "PL"}' ,
'{"monitor_type": "LCD"}'
)
);
INSERT INTO `e_store`.`products`(
`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Walker' ,
'3' ,
'3' ,
JSON_MERGE_PRESERVE(
'{"sensor_type": "CMOS"}' ,
'{"processor": "Digic DV I"}' ,
'{"scanning_system": "progressive"}' ,
'{"mount_type": "PL"}' ,
'{"monitor_type": "LED"}'
)
);
INSERT INTO `e_store`.`products`(
`name` ,
`brand_id` ,
`category_id` ,
`attributes`
)
VALUES(
'Jumper' ,
'3' ,
'3' ,
JSON_MERGE_PRESERVE(
'{"sensor_type": "CMOS"}' ,
'{"processor": "Digic DV I"}' ,
'{"scanning_system": "progressive"}' ,
'{"mount_type": "PL"}' ,
'{"monitor_type": "LCD"}'
)
);
この例では、5つの異なるカメラ製品を宣言しています。
オブジェクトのみがに渡されることに注意してください JSON_MERGE_PRESERVE
関数。 それらのいくつかは、を使用して構築されています JSON_OBJECT
関数。 その他は有効なJSON文字列として渡されています。
の場合 JSON_MERGE_PRESERVE
関数では、キーが複数回繰り返された場合、その値は出力に配列として保持されます。
たとえば、これは同じJSONオブジェクトのコレクションです network
鍵:
SELECT JSON_MERGE_PRESERVE(
'{"network": "GSM"}' ,
'{"network": "CDMA"}' ,
'{"network": "HSPA"}' ,
'{"network": "EVDO"}'
);
これにより、値の配列が生成されます。
Output{"network": ["GSM", "CDMA", "HSPA", "EVDO"]}
これで、この時点で、を使用してクエリを確認できます。 JSON_TYPE
フィールド値タイプを表示する関数:
SELECT JSON_TYPE(attributes) FROM `e_store`.`products`;
このクエリは15を生成します OBJECT
すべての製品(テレビ5台、携帯電話5台、カメラ5台)を表す結果。
これで、JSONフィールドにデータを作成できます。
ステップ3—JSONフィールドからのデータの読み取り
データベースに使用する製品がいくつかあるので、データの読み取りを試すことができます。
JSON型ではない一般的なMySQL値の場合、通常は WHERE
句。 ヒューリスティックに、JSON列を操作する場合、これは機能しません。
JSONフィールドを使用して行を選択する場合は、パス式の概念に精通している必要があります。 パス式はドル記号を使用します($
)およびターゲットオブジェクトキー。
と組み合わせて使用する場合 JSON_EXTRACT
関数を使用すると、指定した列の値を取得できます。
少なくとも1つのUSBポートと1つのHDMIポートを備えたすべてのテレビに関心があるシナリオを考えてみましょう。
SELECT
*
FROM
`e_store`.`products`
WHERE
`category_id` = 1
AND JSON_EXTRACT(`attributes` , '$.ports.usb') > 0
AND JSON_EXTRACT(`attributes` , '$.ports.hdmi') > 0;
への最初の引数 JSON_EXTRACT
関数は、パス式を適用するJSONです。 attributes
桁。 The $
シンボルは、操作するオブジェクトをトークン化します。 The $.ports.usb
と $.ports.hdmi
パス式は、それぞれ「ポートの下でUSBキーを取得する」および「ポートの下でhdmiキーを取得する」という意味になります。
関心のあるキーを抽出したら、大なり記号(>
) それらの上に。
このクエリは3つの結果を生成します。
これらの3つのテレビには、少なくとも1つのUSBポートと1つのHDMIポートがあります。 「ブラビア」モデルと「プロトン」モデルは、これらの条件を満たしていません。
または、 JSON_EXTRACT
関数にはエイリアスがあります ->
クエリを読みやすくするために使用できます。
前のクエリを修正して、 ->
エイリアス:
SELECT
*
FROM
`e_store`.`products`
WHERE
`category_id` = 1
AND `attributes` -> '$.ports.usb' > 0
AND `attributes` -> '$.ports.hdmi' > 0;
これで、JSONフィールドからデータを読み取ることができます。
ステップ4—JSONフィールドのデータを更新する
JSONフィールドのデータを更新できます JSON_INSERT
, JSON_REPLACE
、 と JSON_SET
機能。 これらの関数には、JSONオブジェクトのどの部分を変更するかを指定するためのパス式も必要です。 これらの関数の出力は、変更が適用された有効なJSONオブジェクトです。
まず、JSONフィールドを次のように更新します JSON_INSERT
新しいを追加するには chipset
すべての携帯電話の値が「Qualcomm」のキー:
UPDATE `e_store`.`products`
SET `attributes` = JSON_INSERT(
`attributes` ,
'$.chipset' ,
'Qualcomm'
)
WHERE
`category_id` = 2;
The $.chipset
パス式は、の位置を識別します chipset
オブジェクトのルートにあるプロパティ。
次のクエリを使用して、更新された携帯電話のカテゴリを調べます。
SELECT
*
FROM
`e_store`.`products`
WHERE
`category_id` = 2
「Qualcomm」は現在、すべての携帯電話に搭載されています。
次に、JSONフィールドを更新します JSON_REPLACE
既存のものを変更するには chipset
すべての携帯電話で「QualcommSnapsdragon」という値のキー:
UPDATE `e_store`.`products`
SET `attributes` = JSON_REPLACE(
`attributes` ,
'$.chipset' ,
'Qualcomm Snapdragon'
)
WHERE
`category_id` = 2;
「Qualcomm」は、すべての携帯電話で「QualcommSnapdragon」に置き換えられました。
最後に、JSONフィールドを次のように更新します JSON_SET
新しいを追加するには body_color
すべてのテレビの値が「赤」のキー:
UPDATE `e_store`.`products`
SET `attributes` = JSON_SET(
`attributes` ,
'$.body_color' ,
'red'
)
WHERE
`category_id` = 1;
「赤」の色がすべてのテレビに適用されるようになりました。
これらの機能はすべて同じように見えますが、動作に違いがあります。
The JSON_INSERT
関数は、プロパティがまだ存在しない場合にのみ、プロパティをオブジェクトに追加します。
The JSON_REPLACE
関数は、プロパティが見つかった場合にのみプロパティを置き換えます。
The JSON_SET
関数は、プロパティが見つからない場合はプロパティを追加し、見つからない場合はプロパティを置き換えます。
これで、JSONフィールドからデータを更新できます。
ステップ5—JSONフィールドからのデータの削除
JSONフィールドのデータは JSON_REMOVE
機能と DELETE
.
JSON_REMOVE
JSON列から特定のキー/値を削除できます。
使用する JSON_REMOVE
機能、削除することが可能です mount_type
すべてのカメラのキー/値ペア:
UPDATE `e_store`.`products`
SET `attributes` = JSON_REMOVE(`attributes` , '$.mount_type')
WHERE
`category_id` = 3;
The JSON_REMOVE
関数は、パス式に基づいて指定されたキーを削除した後、更新されたJSONを返します。
または、 DELETE
JSON列を使用した行全体。
使用する DELETE
と JSON_EXTRACT
と LIKE
、Androidオペレーティングシステムの「Jellybean」バージョンを搭載したすべての携帯電話を削除することが可能です。
DELETE FROM `e_store`.`products`
WHERE `category_id` = 2
AND JSON_EXTRACT(`attributes` , '$.os') LIKE '%Jellybean%';
このクエリは、携帯電話の「Desire」モデルと「Passion」モデルを削除します。
特定の属性を操作するには、 JSON_EXTRACT
関数。 まず、 os
携帯電話の特性を抽出します。 そして、 LIKE
演算子はに適用されます DELETE
文字列を含むすべてのレコード Jellybean
.
これで、JSONフィールドからデータを削除できます。
ステップ6—移行の作成
次に、新しいLaravelプロジェクトを作成します。
警告:このWebアプリケーションはチュートリアルのみを目的としており、本番環境では使用しないでください。
ターミナルウィンドウを開き、次のコマンドを実行します。
- composer create-project laravel/laravel estore-example
新しく作成されたプロジェクトディレクトリに移動します。
- cd estore-example
MySQLデータベースを使用するようにLaravelアプリケーションを構成します。
あなたはあなたを修正する必要があるかもしれません .env
設定するファイル DB_DATABASE
, DB_USERNAME
、 と DB_PASSWORD
.
の3つの移行を作成します brands
, categories
、 と products
それぞれ。
作る create_brands
移行:
- php artisan make:migration create_brands
を変更します create_brands.php
次のコード行を使用した移行:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateBrands extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('brands', function(Blueprint $table){
$table->engine = 'InnoDB';
$table->increments('id');
$table->string('name');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('brands');
}
}
作る create_categories
移行:
- php artisan make:migration create_categories
を変更します create_categories.php
次のコード行を使用した移行:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateCategories extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('categories', function(Blueprint $table){
$table->engine = 'InnoDB';
$table->increments('id');
$table->string('name');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('categories');
}
}
The create_products
移行には、インデックスと外部キーのディレクティブも含まれます。
- php artisan make:migration create_products
を変更します create_products.php
次のコード行を使用した移行:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateProducts extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('products', function(Blueprint $table){
$table->engine = 'InnoDB';
$table->increments('id');
$table->string('name');
$table->unsignedInteger('brand_id');
$table->unsignedInteger('category_id');
$table->json('attributes');
$table->timestamps();
// foreign key constraints
$table->foreign('brand_id')->references('id')->on('brands')->onDelete('restrict')->onUpdate('cascade');
$table->foreign('category_id')->references('id')->on('categories')->onDelete('restrict')->onUpdate('cascade');
// indexes
$table->index('brand_id');
$table->index('category_id');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('products');
}
}
に注意してください $table->json('attributes');
移行のステートメント。
注:これは、JSONデータ型をサポートするデータベースエンジンでのみ機能します。
古いバージョンのMySQLなどのエンジンは、これらの移行を実行できません。
メソッドという名前の適切なデータ型を使用して他のタイプのテーブルフィールドを作成するのと同様に、 json
名前のメソッド attributes
.
ステップ7—モデルの作成
次の3つのモデルを作成します brands
, categories
、 と products
それぞれ。
作成する Brand
モデル:
- php artisan make:model Brand
を変更します Brand.php
次のコード行を含むファイル:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Brand extends Model
{
use HasFactory;
// A brand has many products
public function products(){
return $this->hasMany('Product')
}
}
作成する Category
モデル:
- php artisan make:model Category
を変更します Category.php
次のコード行を含むファイル:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
// A category has many products
public function products(){
return $this->hasMany('Product')
}
}
作成する Product
モデル:
- php artisan make:model Product
を変更します Product.php
次のコード行を含むファイル:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
use HasFactory;
public $timestamps = false;
// Cast attributes JSON to array
protected $casts = [
'attributes' => 'array'
];
// Each product has a brand
public function brand(){
return $this->belongsTo('Brand');
}
// Each product has a category
public function category(){
return $this->belongsTo('Category');
}
}
The $casts
キーを持つ配列 attributes
に設定 array
製品がデータベースからフェッチされるときはいつでも、 attributes
JSONは関連する配列に変換されます。 これにより、コントローラーアクションからレコードを更新できます。
ステップ8—製品の作成
このチュートリアルの残りの部分では、カメラ製品のカテゴリに焦点を当てます。
カメラに固有のフィールドを持つフォームを使用してビューを作成します。 簡潔にするために、テレビと携帯電話の製品カテゴリはカバーされませんが、デザインは非常に似ています。
カメラ製品カテゴリのコントローラーを作成します。
- php artisan make:controller CameraController
を変更します CameraController.php
次のコード行を使用します。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class CameraController extends Controller
{
// creates product in database
// using form fields
public function store(Request $request){
// create object and set properties
$camera = new \App\Models\Product();
$camera->name = $request->name;
$camera->brand_id = $request->brand_id;
$camera->category_id = $request->category_id;
$camera->attributes = [
'processor' => $request->processor,
'sensor_type' => $request->sensor_type,
'monitor_type' => $request->monitor_type,
'scanning_system' => $request->scanning_system,
];
// save to database
$camera->save();
// show the created camera
return view('product.camera.show', ['camera' => $camera]);
}
}
これで完了です store
カメラの機能。
を作成してビューを作成します new.blade.php
のファイル resources/views/product/camera
ディレクトリツリー:
<form method="POST" action="/product/camera/store">
@csrf
<table>
<tr>
<td><label for="name">Name</label></td>
<td><input id="name" name="name" type="text"></td>
</tr>
<tr>
<td><label for="brand-id">Brand ID</label></td>
<td>
<select id="brand-id" name="brand_id">
<option value="1">Samsung</option>
<option value="2">Nokia</option>
<option value="3">Canon</option>
</select>
</td>
</tr>
<tr>
<td><label for="attributes-processor">Processor</label></td>
<td><input id="attributes-processor" name="processor" type="text"></td>
</tr>
<tr>
<td><label for="attributes-sensor-type">Sensor Type</label></td>
<td><input id="attributes-sensor-type" name="sensor_type" type="text"></td>
</tr>
<tr>
<td><label for="attributes-monitor-type">Monitor Type</label></td>
<td><input id="attributes-monitor-type" name="monitor_type" type="text"></td>
</tr>
<tr>
<td><label for="attributes-scanning-system">Scanning System</label></td>
<td><input id="attributes-scanning-system" name="scanning_system" type="text"></td>
</tr>
</table>
<input name="category_id" value="3" type="hidden">
<button type="submit">Submit</button>
</form>
The brand_id
ハードコードされたものとして表示されます select
以前に作成された3つのブランドの要素 option
s。 The category_id
に設定されたハードコードされた非表示の入力値として表示されます id
カメラ用。
のルートを変更します routes/web.php
カメラを表示するには:
// ...
use App\Http\Controllers\CameraController;
Route::get('/product/camera/new', function() {
return view('product/camera/new');
});
Route::post(
'/product/camera/store',
[CameraController::class, 'store']
);
次のコマンドを使用してアプリケーションを提供します。
- php artisan serve
次に、 localhost:8000/product/camera/new
)Webブラウザを使用します。 新しいカメラを追加するためのフォームが表示されます。
ステップ9—製品の取得
The $casts
以前に宣言された配列 Product
モデルは、属性を連想配列として扱うことにより、製品の読み取りと編集に役立ちます。
を変更します CamerasController
次のコード行を使用します。
<?php
// ...
class CameraController extends Controller
{
// ... store ...
// fetches a single product
// from database
public function show($id){
$camera = \App\Models\Product::find($id);
return view('product.camera.show', ['camera' => $camera]);
}
}
これで完了です show
カメラの機能。
を作成してビューを作成します show.blade.php
のファイル resources/views/product/camera
ディレクトリツリー:
<table>
<tr>
<td>Name</td>
<td>{{ $camera->name }}</td>
</tr>
<tr>
<td>Brand ID</td>
<td>{{ $camera->brand_id }}</td>
</tr>
<tr>
<td>Category ID</td>
<td>{{ $camera->category_id }}</td>
</tr>
<tr>
<td>Processor</td>
<td>{{ $camera->attributes['processor'] }}</td>
</tr>
<tr>
<td>Sensor Type</td>
<td>{{ $camera->attributes['sensor_type'] }}</td>
</tr>
<tr>
<td>Monitor Type</td>
<td>{{ $camera->attributes['monitor_type'] }}</td>
</tr>
<tr>
<td>Scanning System</td>
<td>{{ $camera->attributes['scanning_system'] }}</td>
</tr>
</table>
のルートを変更します routes/web.php
カメラを表示するには:
// ...
Route::get(
'/product/camera/show/{id}',
[CameraController::class, 'show']
);
次のコマンドを使用してアプリケーションを提供します。
- php artisan serve
次に、有効な id
カメラ製品の場合(例: localhost:8000/product/camera/show/11
)Webブラウザを使用します。 製品のカメラ情報の表が表示されます。 id
「11」の。
ステップ10—製品の編集
のための技術の組み合わせを使用することによって store
と show
、ビューを作成できます edit
既存の製品。
次のようなフォームを作成できます new.blade.php
. 次に、で使用されているものと同様の製品変数を事前に入力します show.blade.php
:
<tr>
<td><label for="attributes-processor">Processor</label></td>
<td><input id="attributes-processor" name="processor" type="text" value="{{ $camera->attributes['processor'] }}"></td>
</tr>
これで、フォームに既存の値が表示され、ユーザーは更新が必要なものを簡単に確認できるようになります。
まず、 id
モデルを取得するために使用されます。 次に、リクエストの値が適用されます。 最後に、新しい値がデータベースに保存されます。
ステップ11—JSON属性に基づく検索
EloquentORMを使用してJSON列をクエリすることもできます。
ユーザーが興味のある属性に基づいてカメラを検索できる検索ページについて考えてみます。
public function search(Request $request){
$cameras = \App\Models\Product::where([
['attributes->processor', 'like', $request->processor],
['attributes->sensor_type', 'like', $request->sensor_type],
['attributes->monitor_type', 'like', $request->monitor_type],
['attributes->scanning_system', 'like', $request->scanning_system]
])->get();
return view('product.camera.search', ['cameras' => $cameras]);
}
取得したレコードは、 product.camera.search
として見る $cameras
コレクション。 これにより、結果をループして、ユーザーの検索要求の条件を満たすカメラを表示できます。
ステップ12—製品の削除
非JSON列属性を使用すると、次のように指定して製品を削除できます。 where
句を呼び出してから、 delete
方法。
たとえば、 id
.
\App\Models\Product::where('id', $id)->delete();
JSON列の場合、 where
単一または複数の属性を使用する句を使用してから、 delete
方法。
\App\Models\Product::where('attributes->sensor_type', 'CMOS')->delete();
}
この例では、このコードは、 sensor_type
属性は「CMOS」に設定されています。
結論
この記事では、JSONデータ型を使用してMySQLデータベースを設計し、LaravelWebアプリケーションを使用してデータベースに接続しました。
データをキーと値のペアとして別のテーブルに保存したり、エンティティの柔軟な属性を操作したりする必要がある場合は、データベース設計の圧縮に大きく貢献する可能性があるため、代わりにJSONデータ型フィールドの使用を検討する必要があります。
さらに深く掘り下げることに興味がある場合は、 MySQLドキュメントは、JSONの概念をさらに探求するための優れたリソースです。
Laravelの詳細については、 Get Started withLaravelに関するテクニカルトークを参照してください。