Использование JSON полей в Laravel Eloquent

В этой статье мы узнаем как хранить JSON в бд MySQL и как легко выбирать и обновлять эти данные с использованием Eloquent.

Прежде всего, вам необходимо проверить, что версия вашей бд MySQL 5.7.8 или выше. Более старые версии не поддерживают хранение json в таблицах.

Примеры для данной статьи будут использовать данные от известной на западе игры Habbo.Данные по мебели

Структура данных

Как вы можете видеть, данные в формате json сгруппированы по двум категориям: типы элементов комнаты и типы элементов стены. Мы получим эту информацию и сохраним ее в таблице нашей базы данных.

Создание миграции

Прежде всего нам нужно сделать миграцию чтобы создать таблицу items и иметь возможность хранить наши данные

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateItemsTable extends Migration
{
    public function up()
    {
        Schema::create('items', function (Blueprint $table) {
            $table->id();
            $table->json('furni');
            $table->string('type');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('items');
    }
}

Как вы уже заметили, мы отметили столбец furni как json.

А вы знали?

При создании миграции с помощью команды artisan make:migration вам не нужно указывать имя миграции с каким либо форматированием, достаточно только сделать это следующим образом:

php artisan make:migration "create items table"

Получение данных

Чтобы получить данные с сайта Habbo, мы создадим крошечную команду, которая будет импортировать эти данные в таблицу items.

Для начала создадим модель

php artisan make:model Item

Затем мы напишем команду, которая выглядит следующим образом:

<?php

namespace App\Console\Commands;

use App\Models\Item;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;
use Symfony\Component\Console\Helper\ProgressBar;

class AddItemsCommand extends Command
{
    private const HASHES_URL = 'https://www.habbo.com/gamedata/hashes2';

    protected $signature = 'add:items';
    protected $description = 'Add items from gamedata';

    public function handle()
    {
        $this->storeFurniData();

        $this->newLine();
        return $this->info('Furni info fetched!');
    }

    private function getFurniDataUrl(): string
    {
        $hashUrl = Http::get(self::HASHES_URL);

        if (! $hashUrl->successful()) {
            $this->error('Furni data could not be fetched.');
        }

        $hashes = collect($hashUrl->json()['hashes']);
        $hashes = $hashes->mapWithKeys(fn($hash) => [$hash['name'] => $hash]);

        $furnidata = $hashes->get('furnidata');
        return "{$furnidata['url']}/{$furnidata['hash']}";
    }

    private function storeFurniData(): void
    {
        $data = Http::get($this->getFurniDataUrl());
        $data = collect($data->json());

        $data = $data->mapWithKeys(fn($items, $key) => [$key => $items]);
        $furniCount = $data->map(fn($items) => count($items['furnitype']))->flatten()->sum();

        $this->info("Trying to fetch {$furniCount} furnis.");
        $progressBar = $this->output->createProgressBar($furniCount);
        $progressBar->start();

        $data->each(fn($types, $type) => collect($types)->each(fn($items) => collect($items)->each(fn($item) => $this->addItem($item, $type, $progressBar))));

        $progressBar->finish();
    }

    private function addItem(array $furni, string $type, ProgressBar $bar): void
    {
        $item = new Item();
        $item->furni = json_encode($furni);
        $item->type = $type;
        $item->save();

        $bar->advance();
    }
}

В коде выше мы получаем URL-адрес данных furni, а затем перебираем элементы для хранения в нашей базе данных. Не забудьте закодировать информацию JSON, как мы делаем в этом примере при добавлении новых строк в таблицу!

Выполнив эту команду, мы получим нашу таблицу элементов, полную данных в течение нескольких секунд.

Обработка данных

Давайте посмотрим на JSON-информацию первой мебели с помощью простого выбора:

\App\Models\Item::first()->furni

{
	"bc": true,
	"id": 13,
	"name": "Beige Bookcase",
	"rare": false,
	"xdim": 1,
	"ydim": 1,
	"adurl": null,
	"buyout": true,
	"offerid": 5,
	"canlayon": false,
	"cansiton": false,
	"category": "shelf",
	"revision": 61856,
	"classname": "shelves_norja",
	"furniline": "iced",
	"canstandon": false,
	"defaultdir": 0,
	"partcolors": {
		"color": [
			"#ffffff",
			"#F7EBBC"
		]
	},
	"rentbuyout": false,
	"description": "For nic naks and books.",
	"environment": null,
	"rentofferid": -1,
	"specialtype": 1,
	"customparams": null,
	"excludeddynamic": false
}

Это то, что включено в первую строку нашей таблицы товаров в столбце furni. Как вы можете видеть, существует множество свойств, которые хранятся в одном столбце!

Приведение JSON к массиву

Можно преобразовать JSON в массив без необходимости использования json_decode. Все, что нам нужно сделать, это добавить это в нашу модель Item.

protected $casts = [
    'furni' => 'array'
];

Теперь каждый раз, когда мы получаем данные из столбца furni, мы получим в ответе массив.

Использование условий JSON Where

Представьте себе, что вы хотите только запросить замороженные предметы мебели, как это можно сделать?

Laravel eloquent предоставляет JSON where, которые помогут нам быстро это исправить:

\App\Models\Item::where('furni->furniline', 'iced')->get()

Данные по реакции замороженного furniline

Как вы можете видеть, нам нужно только запросить столбец JSON с помощью оператора ->.

Запрос массивов JSON по их длине

Что делать, если мы хотим запросить мебель, которая имеет три цвета? Это можно сделать с помощью метода whereJsonLength, который проверит, сколько элементов имеет массив.

\App\Models\Item::whereJsonLength('furni->partcolors->color', 3)->get()

Мебель с тремя цветами отклика данных

И это все, мы получили 534 предмета простым способом!

Обновление данных столбца JSON

Обновление данных JSON также очень легко сделать с помощью синтаксиса ->.

Мы изменим свойство rare на true:

\App\Models\Item::where('furni->furniline', 'rare')->update(['furni->rare' => true])

Редкие данные по реакции furniline

И дело сделано! Давайте проверим, что получилось:

\App\Models\Item::where('furni->furniline', 'rare')->get()

Выводы

На мой взгляд, хранить и обрабатывать данные JSON очень легко с помощью Laravel. От выбора простого значения JSON до массового обновления некоторых данных JSON. Я надеюсь, что эти трюки были вам полезны.

https://davidtorralbo.dev/post/using-json-column-types-in-laravel

Рейтинг
( Пока оценок нет )
Maxyc Webber/ автор статьи
Мне 35 лет. Опыт профессиональной разработки 15 лет. Занимаюсь разработкой и поддержкой корпоративных систем автоматизации бизнеса, а также высоконагруженными проектами. Мне нравится решать нестандартные проблемы бизнеса. Имею опыт формирования команд под проект, налаживания процесса разработки, коммуникации программистов и заказчиков. Есть опыт работы с зарубежными заказчиками (ОАЭ, Польша, Германия, Швейцария).
Понравилась статья? Поделиться с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!:

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.