Массовый upsert в Laravel (Eloquent)

Есть ли способ массового обновления (вставки или обновления, если существует) записей в Laravel (база данных MySQL)?

Скажем, у меня есть таблица с:

[id:1 value:4]
[id:2 value:5]

Я хочу выполнить:

Model::massupsert([
  [id:1 value:100],
  [id:3 value:20]
]);

И таблица после этого будет:

[id:1 value:100]
[id:2 value:5]
[id:3 value:20]

Какую базу данных вы используете?

Jonas Staudenmeir 07.04.2019 14:12

Я использую базу данных mysql.

Yaron 07.04.2019 14:36

В Laravel нет встроенной поддержки upsert (пока). Вы можете использовать этот пакет: github.com/yadakhov/insert-on-duplicate-key

Jonas Staudenmeir 07.04.2019 14:43

Спасибо, это то, что я искал.

Yaron 07.04.2019 15:29

Если вы поставите это как ответ, я отмечу это как решение.

Yaron 07.04.2019 15:30
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Поиск нового уровня в Laravel с помощью MeiliSearch и Scout
Поиск нового уровня в Laravel с помощью MeiliSearch и Scout
Laravel Scout - это популярный пакет, который предоставляет простой и удобный способ добавить полнотекстовый поиск в ваше приложение Laravel. Он...
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
5
5
6 474
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Конечно, вы можете использовать метод updateOrCreate(). Цитата из документация:

You may also come across situations where you want to update an existing model or create a new model if none exists. Laravel provides an updateOrCreate method to do this in one step.

$data = collect([
    ['id' => 1, 'value' => 100],
    ['id' => 3, 'value' => 20]
]);

$data->each(function ($item) {
    Model::updateOrCreate([
        ['id' => $item['id']],
        ['value' => $item['value']]
    ]);
});

Примечание:, если вам нужно обрабатывать много записей одновременно, этот метод может привести к медленной обработке, так как вы создаете/обновляете одну модель в базе данных за раз.

Обновление № 1: сокращение запросов

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

$data = collect([
    ['id' => 1, 'value' => 100],
    ['id' => 3, 'value' => 20]
]);

$models = $data->map(function ($attributes) {
    $model = Model::firstOrCreate([
        ['id' => $attributes['id']],
        ['value' => $attributes['value']]
    ]);

    if (! $model->exists) {
        $model->fill($attributes);
    }

    return $model;
});

list($saved, $unsaved) = $models->partition(function ($model) {
    return $model->exists;
});

Model::insert($unsaved);
$saved->each->update();

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

Спасибо, но я ищу решение, которое приводит к 1 SQL-запросу, а не к нескольким вызовам (для повышения производительности).

Yaron 07.04.2019 15:27

@Yaron Нашли ли вы лучшее решение для уменьшения размера запроса?

Murad Shukurlu 05.04.2020 15:10

В Laravel нет встроенной поддержки UPSERT.

Я создал для этого пакет: https://github.com/staudenmeir/laravel-upsert

Model::upsert([
    ['id' => 1, 'value' => 100],
    ['id' => 3, 'value' => 20],
], 'id', ['value']);

используйте это, и это сработало отлично, только одно, хотя из инструкций вы должны добавить use \Staudenmeir\LaravelUpsert\Eloquent\HasUpsertQueries; к классу модели;

Edrisa Turay 25.01.2021 22:17
Ответ принят как подходящий

Теперь (6 октября 2020 г.) Laravel (v8.10.0) имеет встроенную поддержку upsert. https://github.com/laravel/framework/pull/34698

Model::upsert([
    ['id' => 1, 'value' => 100],
    ['id' => 3, 'value' => 20],
], 'id');

Круто, но похоже, что Laravel просто создает несколько операторов INSERT ... ON DUPLICATE KEY UPDATE, что действительно очень медленно, когда ваш массив больше. Если производительность важна, то использование необработанного оператора один может быть намного быстрее.

Sliq 26.08.2021 17:47

В Laravel 8 теперь есть функция upsert, которую я использую в своем последнем проекте. Я очень наслаждаюсь этим!

https://laravel.com/docs/8.x/queries#update-statements

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

DB::table('flights')->upsert([
    ['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99],
    ['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
], ['departure', 'destination'], ['price']);

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