Thứ ba, 15/09/2020 | 00:00 GMT+7

Làm việc với JSON trong MySQL

Database SQL có xu hướng cứng nhắc. Nếu bạn đã từng làm việc với họ, bạn sẽ đồng ý rằng thiết kế database mặc dù có vẻ dễ dàng hơn nhưng trong thực tế lại phức tạp hơn rất nhiều. Database SQL tin vào cấu trúc, đó là lý do tại sao nó được gọi là ngôn ngữ truy vấn có cấu trúc.

 

Ở phía bên kia của chân trời, ta có database NoSQL, còn gọi là database schemas khuyến khích tính linh hoạt. Trong database ít schemas , không có giới hạn cấu trúc áp đặt, chỉ có dữ liệu được lưu.

Mặc dù mọi công cụ đều có trường hợp sử dụng, nhưng đôi khi mọi thứ đòi hỏi một cách tiếp cận kết hợp.

Điều gì sẽ xảy ra nếu bạn có thể cấu trúc một số phần trong database của bạn và để những phần khác linh hoạt?

MySQL version 5.7.8 giới thiệu kiểu dữ liệu JSON cho phép bạn thực hiện điều đó.

Trong hướng dẫn này, bạn sẽ học.

  1. Cách thiết kế bảng database của bạn bằng cách sử dụng các trường JSON.
  2. Các chức năng dựa trên JSON khác nhau có sẵn trong MYSQL để tạo, đọc, cập nhật và xóa các hàng.
  3. Cách làm việc với các trường JSON bằng Eloquent ORM trong Laravel.

Tại sao sử dụng JSON

Đến đây, có lẽ bạn đang tự hỏi mình tại sao bạn lại muốn sử dụng JSON khi MySQL đã đáp ứng nhiều nhu cầu database ngay cả trước khi nó giới thiệu kiểu dữ liệu JSON.

Câu trả lời nằm trong các trường hợp sử dụng mà bạn có thể sẽ sử dụng phương pháp thay đổi.

Hãy để tôi giải thích bằng một ví dụ.

Giả sử bạn đang xây dựng một ứng dụng web trong đó bạn phải lưu cấu hình / tùy chọn của user trong database .

Nói chung, bạn có thể tạo một bảng database riêng với các trường id , user_id , keyvalue hoặc lưu nó dưới dạng một chuỗi được định dạng mà bạn có thể phân tích cú pháp trong thời gian chạy.

Tuy nhiên, điều này hoạt động tốt đối với một số lượng nhỏ user . Nếu bạn có khoảng một nghìn user và năm khóa cấu hình, bạn đang xem một bảng có năm nghìn bản ghi đề cập đến một tính năng rất nhỏ của ứng dụng của bạn.

Hoặc nếu bạn đang sử dụng tuyến chuỗi được định dạng, mã không liên quan chỉ kết hợp tải server của bạn.

Việc sử dụng trường kiểu dữ liệu JSON để lưu cấu hình của user trong một trường hợp như vậy có thể giúp bạn tiết kiệm không gian cho bảng database và giảm số lượng bản ghi được lưu riêng, giống với số lượng user .

Và bạn có thêm lợi ích là không phải viết bất kỳ mã phân tích cú pháp JSON nào, ORM hoặc thời gian chạy ngôn ngữ sẽ đảm nhiệm việc đó.

Lược đồ

Trước khi đi sâu vào sử dụng tất cả những thứ JSON thú vị trong MySQL, ta cần một database mẫu để sử dụng.

Vì vậy, trước tiên hãy lấy schemas database của ta .

Ta sẽ xem xét trường hợp sử dụng của một cửa hàng trực tuyến chứa nhiều thương hiệu và nhiều loại đồ điện tử.

Vì các thiết bị điện tử khác nhau có các thuộc tính khác nhau (so sánh Macbook với Máy dọn dẹp chân không) mà người mua quan tâm, nên thường sử dụng mẫu Thực thể-thuộc tính-giá trị (EAV) .

Tuy nhiên, vì bây giờ ta có tùy chọn sử dụng kiểu dữ liệu JSON, ta sẽ loại bỏ EAV.

Đầu tiên, database của ta sẽ có tên là e_store và chỉ có ba bảng được đặt tên, brands , categoriesproducts tương ứng.

Các bảng brandscategories của ta sẽ khá giống nhau, mỗi bảng có một id và một trường name .

CREATE DATABASE IF NOT EXISTS `e_store` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;  SET default_storage_engine = INNODB;  CREATE TABLE `e_store`.`brands`(     `id` INT UNSIGNED NOT NULL auto_increment ,     `name` VARCHAR(250) NOT NULL ,     PRIMARY KEY(`id`) );  CREATE TABLE `e_store`.`categories`(     `id` INT UNSIGNED NOT NULL auto_increment ,     `name` VARCHAR(250) NOT NULL ,     PRIMARY KEY(`id`) ); 

Mục tiêu của hai bảng này sẽ là nơi chứa các danh mục sản phẩm và thương hiệu cung cấp các sản phẩm này.

Trong khi ta đang ở đó, ta hãy tiếp tục và gieo một số dữ liệu vào các bảng này để sử dụng sau này.

/* 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');  /* Types of electronic device */ INSERT INTO `e_store`.`categories`(`name`) VALUES     ('Television');  INSERT INTO `e_store`.`categories`(`name`) VALUES     ('Mobilephone');  INSERT INTO `e_store`.`categories`(`name`) VALUES     ('Camera'); 

Bảng thương hiệu

Bảng danh mục

Tiếp theo, là lĩnh vực kinh doanh của hướng dẫn này.

Ta sẽ tạo một bảng products với các trường id , name , brand_id , category_idattributes .

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 ); 

Định nghĩa bảng của ta chỉ định các ràng buộc foreign keys cho các trường brand_idcategory_id , chỉ định rằng chúng tham chiếu đến bảng brandscategories tương ứng. Ta cũng đã chỉ định rằng các hàng được tham chiếu không được phép xóa và nếu được cập nhật, các thay đổi cũng phải phản ánh trong các tham chiếu.

Kiểu cột của trường attributes đã được khai báo là JSON, đây là kiểu dữ liệu root hiện có sẵn trong MySQL. Điều này cho phép ta sử dụng các cấu trúc JSON khác nhau có liên quan trong MySQL trên trường attributes của ta .

Đây là một sơ đồ mối quan hệ thực thể của database đã tạo của ta .

 Database  e_store

Thiết kế database của ta không phải là tốt nhất về hiệu quả và độ chính xác. Không có cột giá trong bảng products và ta có thể làm với việc đưa một sản phẩm vào nhiều danh mục. Tuy nhiên, mục đích của hướng dẫn này không phải để dạy thiết kế database mà là cách mô hình hóa các đối tượng có bản chất khác nhau trong một bảng duy nhất bằng cách sử dụng các tính năng JSON của MySQL.

Hoạt động CRUD

Hãy để ta xem xét cách tạo, đọc, cập nhật và xóa dữ liệu trong trường JSON.

Tạo nên

Tạo bản ghi trong database với trường JSON khá đơn giản.

Tất cả những gì bạn cần làm là thêm JSON hợp lệ làm giá trị trường trong câu lệnh chèn của bạn.

/* Let's sell some televisions */ 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"}}' ); 

Bảng sản phẩm sau khi thêm tivi

Thay vì tự đặt đối tượng JSON, bạn cũng có thể sử dụng hàm JSON_OBJECT sẵn.

Hàm JSON_OBJECT chấp nhận một danh sách các cặp khóa / giá trị ở dạng JSON_OBJECT(key1, value1, key2, value2, ... key(n), value(n)) và trả về một đối tượng JSON.

/* Let's sell some mobilephones */ 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 Lollypop 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"     ) ); 

Bảng sản phẩm sau khi thêm điện thoại di động

Lưu ý hàm JSON_ARRAY trả về một mảng JSON khi được truyền một tập giá trị.

Nếu bạn chỉ định một khóa nhiều lần, thì chỉ cặp khóa / giá trị đầu tiên sẽ được giữ lại. Điều này được gọi là bình thường hóa JSON theo thuật ngữ của MySQL. Ngoài ra, như một phần của quá trình chuẩn hóa, các khóa đối tượng được sắp xếp và khoảng trắng thừa giữa các cặp khóa / giá trị bị loại bỏ.

Một hàm khác mà ta có thể sử dụng để tạo các đối tượng JSON là hàm JSON_MERGE .

Hàm JSON_MERGE nhận nhiều đối tượng JSON và tạo ra một đối tượng tổng hợp duy nhất.

/* Let's sell some cameras */ INSERT INTO `e_store`.`products`(     `name` ,     `brand_id` ,     `category_id` ,     `attributes` ) VALUES(     'Explorer' ,     '3' ,     '3' ,     JSON_MERGE(         '{"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(         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(         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(         '{"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(         '{"sensor_type": "CMOS"}' ,         '{"processor": "Digic DV I"}' ,         '{"scanning_system": "progressive"}' ,         '{"mount_type": "PL"}' ,         '{"monitor_type": "LCD"}'     ) ); 

Bảng sản phẩm sau khi thêm máy ảnh

Có rất nhiều điều xảy ra trong các câu lệnh chèn này và nó có thể hơi khó hiểu. Tuy nhiên, nó là khá đơn giản.

Ta chỉ chuyển các đối tượng đến hàm JSON_MERGE . Một số trong số chúng đã được xây dựng bằng cách sử dụng hàm JSON_OBJECT mà ta đã thấy trước đây trong khi những cái khác đã được chuyển dưới dạng chuỗi JSON hợp lệ.

Trong trường hợp của hàm JSON_MERGE , nếu một khóa được lặp lại nhiều lần, thì giá trị của khóa đó được giữ lại dưới dạng một mảng trong kết quả .

Tôi cho là một bằng chứng về khái niệm.

/* output: {"network": ["GSM", "CDMA", "HSPA", "EVDO"]} */ SELECT JSON_MERGE(     '{"network": "GSM"}' ,     '{"network": "CDMA"}' ,     '{"network": "HSPA"}' ,     '{"network": "EVDO"}' ); 

Ta có thể xác nhận tất cả các truy vấn của ta đã được chạy thành công bằng cách sử dụng hàm JSON_TYPE để cung cấp cho ta loại giá trị trường.

/* output: OBJECT */ SELECT JSON_TYPE(attributes) FROM `e_store`.`products`; 

Thêm thuộc tính là các đối tượng JSON

Đọc

Đúng vậy, ta có một vài sản phẩm trong database của bạn để làm việc.

Đối với các giá trị MySQL điển hình không thuộc loại JSON, mệnh đề where khá dễ hiểu. Chỉ cần chỉ định cột, toán tử và các giá trị bạn cần làm việc.

Về mặt kinh nghiệm, khi làm việc với các cột JSON, điều này không hoạt động.

/* It's not that simple */ SELECT     * FROM     `e_store`.`products` WHERE     attributes = '{"ports": {"usb": 3, "hdmi": 1}, "screen": "50 inch", "speakers": {"left": "10 watt", "right": "10 watt"}, "resolution": "2048 x 1152 pixels"}'; 

Khi bạn muốn thu hẹp các hàng bằng cách sử dụng trường JSON, bạn nên làm quen với khái niệm biểu thức đường dẫn.

Định nghĩa đơn giản nhất của biểu thức đường dẫn (nghĩ rằng bộ chọn JQuery) là nó được sử dụng để chỉ định phần nào của tài liệu JSON sẽ làm việc.

Phần thứ hai của câu đố là hàm JSON_EXTRACT chấp nhận một biểu thức đường dẫn để chuyển qua JSON.

Giả sử ta quan tâm đến nhiều loại TV có ít nhất một cổng USB và HDMI.

SELECT     * FROM     `e_store`.`products` WHERE     `category_id` = 1 AND JSON_EXTRACT(`attributes` , '$.ports.usb') > 0 AND JSON_EXTRACT(`attributes` , '$.ports.hdmi') > 0; 

Chọn bản ghi theo thuộc tính JSON

Đối số đầu tiên cho hàm JSON_EXTRACT là JSON để áp dụng biểu thức đường dẫn là cột attributes . Biểu tượng $ mã hóa đối tượng để làm việc. Các biểu thức đường dẫn $.ports.usb$.ports.hdmi dịch thành "lấy khóa usb dưới các cổng" và "lấy khóa hdmi dưới các cổng" tương ứng.

Khi ta đã extract các khóa mà ta quan tâm, sẽ khá đơn giản để sử dụng các toán tử MySQL chẳng hạn như > trên chúng.

Ngoài ra, hàm JSON_EXTRACT có alias -> mà bạn có thể sử dụng để làm cho các truy vấn của bạn dễ đọc hơn.

Sửa đổi truy vấn trước đó của ta .

SELECT     * FROM     `e_store`.`products` WHERE     `category_id` = 1 AND `attributes` -> '$.ports.usb' > 0 AND `attributes` -> '$.ports.hdmi' > 0; 

Cập nhật

Để cập nhật các giá trị JSON, ta sẽ sử dụng các JSON_INSERT , JSON_REPLACEJSON_SET . Các hàm này cũng yêu cầu một biểu thức đường dẫn để chỉ định những phần nào của đối tượng JSON cần sửa đổi.

Đầu ra của các hàm này là một đối tượng JSON hợp lệ với các thay đổi được áp dụng.

Hãy để ta sửa đổi tất cả điện thoại di động để có thuộc tính chipset.

UPDATE `e_store`.`products` SET `attributes` = JSON_INSERT(     `attributes` ,     '$.chipset' ,     'Qualcomm' ) WHERE     `category_id` = 2; 

Điện thoại di động cập nhật

Biểu thức đường dẫn $.chipset xác định vị trí của thuộc tính chipset nằm ở root của đối tượng.

Hãy để ta cập nhật thuộc tính chipset để mô tả nhiều hơn bằng cách sử dụng hàm JSON_REPLACE .

UPDATE `e_store`.`products` SET `attributes` = JSON_REPLACE(     `attributes` ,     '$.chipset' ,     'Qualcomm Snapdragon' ) WHERE     `category_id` = 2; 

Điện thoại di động cập nhật

Dễ như ăn bánh!

Cuối cùng, ta có hàm JSON_SET mà ta sẽ sử dụng để chỉ định tivi của ta có nhiều màu sắc.

UPDATE `e_store`.`products` SET `attributes` = JSON_SET(     `attributes` ,     '$.body_color' ,     'red' ) WHERE     `category_id` = 1; 

TV cập nhật

Tất cả các chức năng này có vẻ giống hệt nhau nhưng có sự khác biệt trong cách chúng hoạt động.

Hàm JSON_INSERT sẽ chỉ thêm thuộc tính vào đối tượng nếu nó chưa tồn tại.

Hàm JSON_REPLACE thay thế thuộc tính nếu nó được tìm thấy.

Hàm JSON_SET sẽ thêm thuộc tính nếu không tìm thấy nó, hãy thay thế nó.

Xóa bỏ

Có hai phần để xóa mà ta sẽ xem xét.

Đầu tiên là xóa một khóa / giá trị nhất định khỏi các cột JSON của bạn, trong khi thứ hai là xóa các hàng bằng cột JSON.

Giả sử ta không còn cung cấp thông tin mount_type cho máy ảnh và muốn xóa thông tin này cho tất cả máy ảnh.

Ta sẽ làm điều đó bằng cách sử dụng hàm JSON_REMOVE trả về JSON đã cập nhật sau khi loại bỏ khóa được chỉ định dựa trên biểu thức đường dẫn.

UPDATE `e_store`.`products` SET `attributes` = JSON_REMOVE(`attributes` , '$.mount_type') WHERE     `category_id` = 3; 

Máy ảnh sau khi loại bỏ thuộc tính mount_type

Đối với trường hợp thứ hai, ta cũng không cung cấp điện thoại di động có version Jellybean của hệ điều hành Android nữa.

DELETE FROM `e_store`.`products` WHERE `category_id` = 2 AND JSON_EXTRACT(`attributes` , '$.os') LIKE '%Jellybean%'; 

 Ta  không bán Jellybeans nữa!

Như đã nêu trước đây, làm việc với một thuộc tính cụ thể yêu cầu sử dụng hàm JSON_EXTRACT vì vậy để áp dụng toán tử LIKE , trước tiên ta đã extract thuộc tính os của điện thoại di động (với sự trợ giúp của category_id ) và xóa tất cả các bản ghi có chứa chuỗi Jellybean .

Lớp lót cho các ứng dụng web

Ngày xưa của việc trực tiếp làm việc với database đã lùi xa ta .

Ngày nay, các khung công tác cách ly các nhà phát triển khỏi các hoạt động cấp thấp hơn và gần như cảm thấy xa lạ đối với một người cuồng khung công tác khi không thể chuyển kiến thức database của bạn thành một trình ánh xạ quan hệ đối tượng.

Với mục đích không khiến các nhà phát triển như vậy đau lòng và băn khoăn về sự tồn tại và mục đích của họ trong vũ trụ, ta sẽ xem xét cách hoạt động của các cột JSON trong framework Laravel .

Ta sẽ chỉ tập trung vào các phần trùng lặp với chủ đề của ta liên quan đến các cột JSON. Hướng dẫn chuyên sâu về khung công tác Laravel nằm ngoài phạm vi của phần này.

Tạo cuộc di chuyển

Đảm bảo cấu hình ứng dụng Laravel của bạn để sử dụng database MySQL.

Ta sẽ tạo ba lần di chuyển cho các brands , categoriesproducts tương ứng.

$ php artisan make:migration create_brands $ php artisan make:migration create_categories $ php artisan make:migration create_products 

Việc di chuyển create_brandscreate_categories khá giống nhau và là quy định dành cho các nhà phát triển Laravel.

/* database/migrations/create_brands.php */  <?php  use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration;  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::drop('brands');     } }  /* database/migrations/create_categories.php */  <?php  use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration;  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::drop('categories');     } }  

Quá trình di chuyển create_products cũng sẽ có các chỉ thị cho các index và foreign keys .

/* database/migrations/create_products */  <?php  use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration;  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::drop('products');     } } 

Hãy chú ý đến $table->json('attributes'); tuyên bố trong quá trình di chuyển.

Cũng giống như tạo bất kỳ trường bảng nào khác bằng cách sử dụng phương thức có tên kiểu dữ liệu thích hợp, ta đã tạo một cột JSON bằng phương thức json với các attributes tên.

Ngoài ra, điều này chỉ hoạt động đối với các công cụ database hỗ trợ kiểu dữ liệu JSON.

Các công cụ, chẳng hạn như các version MySQL cũ hơn sẽ không thể thực hiện các quá trình di chuyển này.

Tạo mô hình

Ngoài các hiệp hội, không cần thiết nhiều để cài đặt các mô hình của ta , vì vậy hãy nhanh chóng lướt qua chúng.

/* app/Brand.php */  <?php  namespace App;  use Illuminate\Database\Eloquent\Model;  class Brand extends Model {     // A brand has many products     public function products(){         return $this->hasMany('Product')     } }  /* app/Category.php */  <?php  namespace App;  use Illuminate\Database\Eloquent\Model;  class Category extends Model {     // A category has many products     public function products(){         return $this->hasMany('Product')     } }  /* app/Product.php */  <?php  namespace App;  use Illuminate\Database\Eloquent\Model;  class Product extends Model {     // 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');     } } 

, mô hình Product của ta cần được đề cập đặc biệt.

Mảng $casts có các attributes khóa attributes đặt thành array đảm bảo khi nào sản phẩm được tìm nạp từ database , các attributes JSON của nó sẽ được chuyển đổi thành một mảng được liên kết.

Ta sẽ xem phần sau của hướng dẫn cách điều này tạo điều kiện cho ta cập nhật các bản ghi từ các hành động của bộ điều khiển của ta .

Hoạt động tài nguyên

Tạo một sản phẩm

Nói về bảng quản trị, các thông số để tạo một sản phẩm có thể đến qua các con đường khác nhau vì ta có một số danh mục sản phẩm. Bạn cũng có thể có các chế độ xem khác nhau để tạo, chỉnh sửa, hiển thị và xóa sản phẩm.

Ví dụ: biểu mẫu thêm máy ảnh yêu cầu các trường nhập khác với biểu mẫu thêm điện thoại di động để chúng đảm bảo các chế độ xem riêng biệt.

Hơn nữa, khi bạn có dữ liệu đầu vào của user , hầu hết bạn sẽ chạy nó thông qua trình xác thực yêu cầu, riêng biệt cho máy ảnh và điện thoại di động.

Bước cuối cùng là tạo sản phẩm thông qua Eloquent.

Ta sẽ tập trung vào tài nguyên máy ảnh cho phần còn lại của hướng dẫn này. Các sản phẩm khác có thể được giải quyết bằng cách sử dụng mã được production theo cách tương tự.

Giả sử ta đang lưu một máy ảnh và các trường biểu mẫu được đặt tên là thuộc tính máy ảnh tương ứng, đây là hành động của bộ điều khiển.

// creates product in database // using form fields public function store(Request $request){     // create object and set properties     $camera = new \App\Product();     $camera->name = $request->name;     $camera->brand_id = $request->brand_id;     $camera->category_id = $request->category_id;     $camera->attributes = json_encode([         '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]); } 

Tìm nạp sản phẩm

Nhớ lại mảng $casts mà ta đã khai báo trước đó trong mô hình Product . Nó sẽ giúp ta đọc và chỉnh sửa một sản phẩm bằng cách coi các thuộc tính như một mảng kết hợp.

// fetches a single product // from database public function show($id){     $camera = \App\Product::find($id);     return view('product.camera.show', ['camera' => $camera]); } 

Chế độ xem của bạn sẽ sử dụng biến $camera theo cách sau.

<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> 

Chỉnh sửa Sản phẩm

Như trong phần trước, bạn có thể dễ dàng tìm nạp một sản phẩm và chuyển nó đến chế độ xem, trong trường hợp này sẽ là chế độ xem chỉnh sửa.

Bạn có thể sử dụng biến sản phẩm để điền trước các trường biểu mẫu trên trang chỉnh sửa.

Cập nhật sản phẩm dựa trên đầu vào của user sẽ khá giống với hành động của store mà ta đã thấy trước đó, chỉ khác là thay vì tạo một sản phẩm mới, bạn sẽ tìm nạp nó trước từ database trước khi cập nhật.

Tìm kiếm dựa trên các thuộc tính JSON

Phần cuối cùng của câu đố vẫn cần thảo luận là truy vấn các cột JSON bằng Eloquent ORM.

Nếu bạn có trang tìm kiếm cho phép tìm kiếm máy ảnh dựa trên thông số kỹ thuật của chúng do user cung cấp, bạn có thể làm như vậy bằng mã sau.

// searches cameras by user provided specifications public function search(Request $request){     $cameras = \App\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]); } 

Các bản ghi đã truy xuất bây giờ sẽ có sẵn cho chế độ xem product.camera.search dưới dạng bộ sưu tập $cameras .

Xóa sản phẩm

Sử dụng thuộc tính cột không phải JSON, bạn có thể xóa các sản phẩm bằng cách chỉ định mệnh đề where và sau đó gọi phương thức delete .

Ví dụ, trong trường hợp ID.

\App\Product::where('id', $id)->delete(); 

Đối với các cột JSON, hãy chỉ định mệnh đề where bằng cách sử dụng một hoặc nhiều thuộc tính và sau đó gọi phương thức delete .

// deletes all cameras with the sensor_type attribute as CMOS \App\Product::where('attributes->sensor_type', 'CMOS')->delete(); } 

Rèm cửa

Ta hầu như không bị trầy xước khi nói đến việc sử dụng các cột JSON trong MySQL.

Khi nào bạn cần lưu dữ liệu dưới dạng các cặp khóa / giá trị trong một bảng riêng biệt hoặc làm việc với các thuộc tính linh hoạt cho một thực thể, bạn nên cân nhắc sử dụng trường kiểu dữ liệu JSON thay vì nó có thể góp phần lớn vào việc nén thiết kế database của bạn.

Nếu bạn quan tâm đến việc tìm hiểu sâu hơn, tài liệu MySQL là một tài nguyên tuyệt vời để khám phá các khái niệm JSON sau này.

Tôi hy vọng bạn thấy hướng dẫn này thú vị và có kiến thức. Cho đến phần tiếp theo của tôi, mã hóa hạnh phúc!


Tags:

Các tin liên quan

Cách cài đặt MySQL trên Ubuntu 20.04
2020-07-30
Cách cài đặt MySQL trên Ubuntu 20.04 [Quickstart]
2020-07-30
Cách triển khai Laravel 7 và MySQL trên Kubernetes bằng Helm
2020-06-23
Cách đặt lại mật khẩu gốc MySQL hoặc MariaDB của bạn
2020-05-05
Cách sử dụng Kiểu dữ liệu MySQL BLOB để lưu trữ image bằng PHP trên Ubuntu 18.04
2020-05-05
Cách cài đặt MySQL trên Ubuntu 18.04
2020-04-21
Cách cài đặt MySQL trên CentOS 8
2020-03-18
Cách triển khai phân trang trong MySQL với PHP trên Ubuntu 18.04
2020-01-29
Cách tối ưu hóa truy vấn MySQL với bộ đệm ProxySQL trên Ubuntu 16.04
2019-12-30
Cách cấu hình Cụm Galera với MySQL trên server Ubuntu 18.04
2019-12-16