Inserimento di massa in Laravel usando eloquente ORM


156

Come possiamo eseguire inserimenti di database di massa in Laravel usando Eloquent ORM?

Voglio realizzare questo in Laravel: https://stackoverflow.com/a/10615821/600516 ma sto ottenendo il seguente errore.

SQLSTATE [HY093]: numero parametro non valido: parametri nominali e posizionali misti.


1
Hai una has_manyrelazione con i tuoi modelli?
PapaSmurf,

1
@jonathandey no al momento non ho relazioni
phoenixwizard

@DavidBarker ho provato a formare la stringa quesr usando un ciclo for. Ho anche provato a utilizzare le transazioni in laravel.
phoenixwizard,

@AramBhusal Potresti pubblicare il tuo codice? Sono sicuro di avere un codice qui che ti aiuterà.
David Barker,

Risposte:


302

Puoi solo usare Eloquent::insert().

Per esempio:

$data = array(
    array('name'=>'Coder 1', 'rep'=>'4096'),
    array('name'=>'Coder 2', 'rep'=>'2048'),
    //...
);

Coder::insert($data);

2
Questo vale ancora per Laravel 4?
Adotta

4
@advait: sì, si applica ancora a Laravel 4.
Ola

37
Vale la pena notare che in realtà non tocca Eloquent. Inoltra semplicemente la chiamata al Query\Builder@insert()metodo. Non è possibile inserire in modo efficiente più righe con Eloquent, né offre alcun metodo per inserimenti di massa.
Jarek Tkaczyk,

6
@CanVural cosa dovremmo fare per aggiornare / creare anche i timestamp?
Milano Maharjan,

3
Questo utilizzerà un inserto. Quindi, dato un array abbastanza grande, fallirà.
patrox,

72

Siamo in grado di aggiornare la risposta GTF per aggiornare facilmente i timestamp

$data = array(
    array(
        'name'=>'Coder 1', 'rep'=>'4096',
        'created_at'=>date('Y-m-d H:i:s'),
        'modified_at'=> date('Y-m-d H:i:s')
       ),
    array(
         'name'=>'Coder 2', 'rep'=>'2048',
         'created_at'=>date('Y-m-d H:i:s'),
         'modified_at'=> date('Y-m-d H:i:s')
       ),
    //...
);

Coder::insert($data);

Aggiornamento: per semplificare la data in cui possiamo usare il carbonio come suggerito da @Pedro Moreira

$now = Carbon::now('utc')->toDateTimeString();
$data = array(
    array(
        'name'=>'Coder 1', 'rep'=>'4096',
        'created_at'=> $now,
        'modified_at'=> $now
       ),
    array(
         'name'=>'Coder 2', 'rep'=>'2048',
         'created_at'=> $now,
         'modified_at'=> $now
       ),
    //...
);

Coder::insert($data);

AGGIORNAMENTO2: per laravel 5, utilizzare updated_atinvece dimodified_at

$now = Carbon::now('utc')->toDateTimeString();
$data = array(
    array(
        'name'=>'Coder 1', 'rep'=>'4096',
        'created_at'=> $now,
        'updated_at'=> $now
       ),
    array(
         'name'=>'Coder 2', 'rep'=>'2048',
         'created_at'=> $now,
         'updated_at'=> $now
       ),
    //...
);

Coder::insert($data);

42
Oppure utilizzare Carbon all'inizio dello script per definire una $nowvariabile $now = Carbon::now('utc')->toDateTimeString();. Quindi utilizzare solo 'created_at' => $now, 'updated_at' => $nowper ogni inserimento.
Pedro Moreira,

2
Come possiamo ottenere tutti gli ID delle righe appena inserite?
akshaykumar6,

2
Perché 'utc'? È la preferenza del progetto o eloquent funziona sempre in "utc"?
Pilat

6
Non voglio iniziare un grande argomento "spazi contro tab", ma per favore, salva i timestamp in UTC! Ti farà risparmiare un sacco di dolore in seguito! Pensa agli utenti a livello globale :)
iSS il

2
Se posso chiedere, qual è il grande bisogno Carbonin questa situazione? Cosa c'è che non va date("Y-m-d H:i:s")?
Ifedi Okonkwo,

30

Per chi sta leggendo questo, controlla il createMany()metodo .

/**
 * Create a Collection of new instances of the related model.
 *
 * @param  array  $records
 * @return \Illuminate\Database\Eloquent\Collection
 */
public function createMany(array $records)
{
    $instances = $this->related->newCollection();

    foreach ($records as $record) {
        $instances->push($this->create($record));
    }

    return $instances;
}

28
Questo non è ciò che si chiama inserimento di massa. A causa della scarsa implementazione, questa funzione preparerà ed eseguirà la stessa query una volta per articolo.
Paul Spiegel

Vale la pena notare che questo è un metodo di relazione, che non può essere chiamato direttamente dal modello, ad es Model::createMany() .
scavare il

24

Ecco come lo fai in modo più eloquente,

    $allintests = [];
    foreach($intersts as $item){ //$intersts array contains input data
        $intestcat = new User_Category();
        $intestcat->memberid = $item->memberid;
        $intestcat->catid= $item->catid;
        $allintests[] = $intestcat->attributesToArray();
    }
    User_Category::insert($allintests);

3

L'ho cercato molte volte, finalmente utilizzato personalizzato timestampscome di seguito:

$now = Carbon::now()->toDateTimeString();
Model::insert([
    ['name'=>'Foo', 'created_at'=>$now, 'updated_at'=>$now],
    ['name'=>'Bar', 'created_at'=>$now, 'updated_at'=>$now],
    ['name'=>'Baz', 'created_at'=>$now, 'updated_at'=>$now],
    ..................................
]);

2

Eloquent::insert è la soluzione corretta ma non aggiorna i timestamp, quindi puoi fare qualcosa come sotto

 $json_array=array_map(function ($a) { 
                        return array_merge($a,['created_at'=> 
                                            Carbon::now(),'updated_at'=> Carbon::now()]
                                           ); 
                                     }, $json_array); 
 Model::insert($json_array);

L'idea è di aggiungere Created_at e Updated_at sull'intero array prima di eseguire l'inserimento


0

Da Laravel 5.7 con Illuminate\Database\Query\Builderte puoi usare il metodo insertUsing.

$query = [];
foreach($oXML->results->item->item as $oEntry){
    $date = date("Y-m-d H:i:s")
    $query[] = "('{$oEntry->firstname}', '{$oEntry->lastname}', '{$date}')";
}

Builder::insertUsing(['first_name', 'last_name', 'date_added'], implode(', ', $query));

-1
$start_date = date('Y-m-d h:m:s');        
        $end_date = date('Y-m-d h:m:s', strtotime($start_date . "+".$userSubscription['duration']." months") );
        $user_subscription_array = array(
          array(
            'user_id' => $request->input('user_id'),
            'user_subscription_plan_id' => $request->input('subscription_plan_id'),
            'name' => $userSubscription['name'],
            'description' => $userSubscription['description'],
            'duration' => $userSubscription['duration'],
            'start_datetime' => $start_date,
            'end_datetime' => $end_date,
            'amount' => $userSubscription['amount'],
            'invoice_id' => '',
            'transection_datetime' => '',
            'created_by' => '1',
            'status_id' => '1', ),
array(
            'user_id' => $request->input('user_id'),
            'user_subscription_plan_id' => $request->input('subscription_plan_id'),
            'name' => $userSubscription['name'],
            'description' => $userSubscription['description'],
            'duration' => $userSubscription['duration'],
            'start_datetime' => $start_date,
            'end_datetime' => $end_date,
            'amount' => $userSubscription['amount'],
            'invoice_id' => '',
            'transection_datetime' => '',
            'created_by' => '1',
            'status_id' => '1', )
        );
        dd(UserSubscription::insert($user_subscription_array));

UserSubscriptionè il nome del mio modello. Questo restituirà "true" se inserisci correttamente altrimenti "false".


-1

Forse un modo più Laravel per risolvere questo problema è usare una collezione e inserirla in loop inserendola con il modello sfruttando i timestamp.

<?php

use App\Continent;
use Illuminate\Database\Seeder;

class InitialSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        collect([
            ['name' => 'América'],
            ['name' => 'África'],
            ['name' => 'Europa'],
            ['name' => 'Asia'],
            ['name' => 'Oceanía'],
        ])->each(function ($item, $key) {
            Continent::forceCreate($item);
        });
    }
}

MODIFICARE:

Ci scusiamo per il mio malinteso. Per l'inserimento di massa questo potrebbe aiutare e forse con questo puoi fare buone seminatrici e ottimizzarle un po '.

<?php

use App\Continent;
use Carbon\Carbon;
use Illuminate\Database\Seeder;

class InitialSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $timestamp = Carbon::now();
        $password = bcrypt('secret');

        $continents = [
            [
                'name' => 'América'
                'password' => $password,
                'created_at' => $timestamp,
                'updated_at' => $timestamp,
            ],
            [
                'name' => 'África'
                'password' => $password,
                'created_at' => $timestamp,
                'updated_at' => $timestamp,
            ],
            [
                'name' => 'Europa'
                'password' => $password,
                'created_at' => $timestamp,
                'updated_at' => $timestamp,
            ],
            [
                'name' => 'Asia'
                'password' => $password,
                'created_at' => $timestamp,
                'updated_at' => $timestamp,
            ],
            [
                'name' => 'Oceanía'
                'password' => $password,
                'created_at' => $timestamp,
                'updated_at' => $timestamp,
            ],
        ];

        Continent::insert($continents);
    }
}

1
Questo crea una query per articolo. Non è un inserimento in blocco.
Emile Bergeron,

1
@EmileBergeron Sono d'accordo con te. Ho modificato il mio post, quindi forse questo potrebbe aiutare ad avere un buon inserimento di massa. Considerando di lasciare le attività che richiedono molto tempo fuori dal circuito (carbon, bcrypt) questo può farti risparmiare un sacco di tempo.
Francisco Daniel,

-1

Per l'inserimento delle relazioni di categoria mi sono imbattuto nello stesso problema e non avevo idea, tranne che nel mio modello eloquente ho usato Self () per avere un'istanza della stessa classe in foreach per registrare più salvataggi e ID di acquisizione.

foreach($arCategories as $v)
{                
    if($v>0){
        $obj = new Self(); // this is to have new instance of own
        $obj->page_id = $page_id;
        $obj->category_id = $v;
        $obj->save();
    }
}

senza "$ obj = new Self ()" salva solo un singolo record (quando $ obj era $ questo)


-4

Problema risolto ... Modifica tabella per migrare

$table->timestamp('created_at')->nullable()->useCurrent();

Soluzione:

Schema::create('spider_news', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->string('source')->nullable();
    $table->string('title')->nullable();
    $table->string('description')->nullable();
    $table->string('daterss')->nullable();

    $table->timestamp('created_at')->useCurrent();
    $table->timestamp('updated_at')->useCurrent();
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.