0
votes

Mass upsert à Laravel (Eloquent)

Existe-t-il un moyen d'upsert en masse (insérer ou mettre à jour s'il existe) des enregistrements dans Laravel (base de données MySQL)?

Disons que j'ai une table avec:

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

Je veux jouer:

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

Et la table après être:

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


5 commentaires

Quelle base de données utilisez-vous?


J'utilise la base de données mysql.


Laravel n'a pas (encore) de support natif d'upsert. Vous pouvez utiliser ce package: github.com/yadakhov/insert-on-duplicate-key


Merci, c'est ce que je cherchais.


Si vous le mettez comme réponse, je le marquerai comme la solution.


3 Réponses :


1
votes

Bien sûr, vous pouvez utiliser la méthode updateOrCreate() . Citant la documentation :

Vous pouvez également rencontrer des situations dans lesquelles vous souhaitez mettre à jour un modèle existant ou créer un nouveau modèle s'il n'en existe pas. Laravel fournit une méthode updateOrCreate pour ce faire en une seule étape.

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

Remarque: si vous devez traiter plusieurs enregistrements à la fois, cette méthode peut ralentir le traitement, car vous créez / mettez à jour un modèle à la fois dans la base de données.

Mise à jour n ° 1: réduire les requêtes

Vous pouvez alors réduire un peu le nombre de requêtes avec firstOrNew , car vous insérez simplement en bloc les nouveaux enregistrements dans la base de données, mais vous devez actuellement mettre à jour manuellement les enregistrements déjà existants un par un:

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

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

Actuellement, pour faire cela avec une seule requête, vous devez utiliser un package comme suggéré par Jonas Staudenmeir dans les commentaires.


2 commentaires

Merci mais je recherche une solution qui se traduit par 1 requête SQL et non par plusieurs appels (pour de meilleures performances)


@Yaron Avez-vous trouvé une meilleure solution pour réduire la taille de la requête?



3
votes

Laravel n'a pas de support natif d'UPSERT.

J'ai créé un package pour cela: https://github.com/staudenmeir/laravel-upsert

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


0 commentaires

2
votes

Maintenant, Laravel a upsert support natif d' upsert . https://github.com/laravel/framework/pull/34698

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


0 commentaires