Как я могу сохранить несколько моделей в Laravel, используя только один запрос к базе данных?

Мне нужно обновить каждую строку моей таблицы, связанную с моделью MyModel. Каждое обновление требует выполнения PHP-кода. В моем случае это не проблема, но мне было интересно, как это сделать более эффективно?

MyModel::chunk(1000, function (Collection $collection) {
     foreach ($collection as $model) {
         $pascalCaseModelName = $model->modelName;
         $myModel->modelAlias = Str::snake($pascalCaseModelName);
         $myModel->save();
     }
});

Сейчас я сохраняю каждую модель после обработки. Это означает, что запрос к базе данных выполняется для каждой модели. Интересно, можно ли сохранить целый фрагмент с помощью оператора on, который вместо этого запускает один запрос к базе данных.

Единственное решение, которое я смог найти, это метод saveMany. Но это применимо только к отношениям.

Вариант А — использовать функции SQL напрямую, как в этом вопросе/ответе: stackoverflow.com/questions/62670745/…, в противном случае это зависит от того, как часто вы это используете. Если это только один раз, то есть для «заполнения» недостающих данных, которые теперь будут добавляться при создании/обновлении записей, не беспокойтесь о производительности слишком сильно; это миграция данных в этот момент.

Tim Lewis 25.04.2023 17:50

@TimLewis да, это просто «заполнить» недостающие данные, и производительность не проблема. Мне просто любопытно, предоставляет ли Laravel функции для этого.

Timo 25.04.2023 17:54

@ Тимо, я бы просто сделал $collection->each() вместо MyModel::chunk(1000,). Коллекция уже может проходить по каждой записи, не нужно чанковать

matiaslauriti 25.04.2023 17:58

Попался. Методы Laravel, как правило, фокусируются на одной модели, и save() выполняет UPDATE запрос для этой конкретной строки через UPDATE ... WHERE id = .... Вы можете попытаться разбить обновления на части и выполнить их все в одном операторе (или в нескольких, IIRC есть ограничение). Но опять же, все это на самом деле только фактор, если производительность является проблемой.

Tim Lewis 25.04.2023 17:59
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
4
111
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы пробовали это?

MyModel::chunk(1000, function (Collection $collection) {
     $updates = [];

     foreach ($collection as $model) {
         $pascalCaseModelName = $model->modelName;
         $updates[] = [
            'id' => $model->id,
            'model_alias' => Str::snake($pascalCaseModelName),
         ];
     }

     if (!empty($updates)) {
         DB::table('my_models')->update($updates, 'id');
     }
});

Спасибо за предложение. Отличная идея! Посмотрите на мой собственный ответ, я использовал метод upsert, чтобы заставить код работать.

Timo 26.04.2023 11:04
Ответ принят как подходящий

По предложению Захариаса мне удалось решить проблему. Но я использовал метод upsert вместо update.

MyModel::chunk(1000, function (Collection $collection) {
    $updates = [];
    
    foreach ($collection as $model) {
        $pascalCaseModelName = $model->modelName;
        $updates[] = [
            'id' => $model->id,
            'model_alias' => Str::snake($pascalCaseModelName),
        ];
    }

    DB::table('my_models')->upsert(
        $updates,
        ['id'], 
        ['model_alias']
    );
});

Хотя update может обновлять несколько записей, он не может вставлять разные значения для каждой модели. может. Смотрите https://laravel.com/docs/10.x/queries#upserts

Привет, мне интересно, как это работает? $updates[] = [ 'id' => $model->id, 'model_alias' => Str::snake($pascalCaseModelName), ]; не будет ли значение переменной $updates заменяться на каждой итерации? или это то же самое, что и array_push()?

Yusuf Giovanno 26.04.2023 11:14

@YusufGiovanno Да, это то же самое, что и array_push. $updates[] = ... — это сокращение для добавления элементов в массив в PHP.

Timo 26.04.2023 12:19

Теперь это новое для меня, спасибо большое, чувак

Yusuf Giovanno 26.04.2023 14:49

Другие вопросы по теме