Penyisipan Massal di Laravel menggunakan ORM yang fasih

156

Bagaimana kita bisa melakukan penyisipan basis data massal di Laravel menggunakan Eloquent ORM?

Saya ingin menyelesaikan ini di Laravel: https://stackoverflow.com/a/10615821/600516 tapi saya mendapatkan kesalahan berikut.

SQLSTATE [HY093]: Nomor parameter tidak valid: nama campuran dan parameter posisi.

phoenixwizard
sumber
1
Apakah Anda memiliki has_manyhubungan dengan model Anda?
PapaSmurf
1
@jonathandey tidak, saya tidak punya hubungan saat ini
phoenixwizard
@ Davidvidark saya telah mencoba membentuk string quesr menggunakan for loop. Saya juga sudah mencoba menggunakan transaksi di laravel.
phoenixwizard
@AramBhusal Bisakah Anda mem-posting kode Anda? Saya yakin saya memiliki beberapa kode di sini yang akan membantu Anda.
David Barker
Pernahkah Anda melihat laravel.com/docs/database/eloquent#mass-assignment ?
BenjaminRH

Jawaban:

302

Anda bisa menggunakannya Eloquent::insert().

Sebagai contoh:

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

Coder::insert($data);
GTF
sumber
2
Apakah ini masih berlaku untuk Laravel 4?
advait
4
@ advait: ya, itu masih berlaku untuk Laravel 4.
Ola
37
Patut dicatat bahwa itu tidak menyentuh Eloquentsebenarnya. Itu hanya proksi panggilan ke Query\Builder@insert()metode. Tidak ada cara untuk menyisipkan beberapa baris secara efisien dengan Eloquent, juga tidak menawarkan metode apa pun untuk sisipan massal.
Jarek Tkaczyk
6
@CanVural apa yang harus kita lakukan untuk memperbarui / membuat cap waktu juga?
Milan Maharjan
3
Ini akan menggunakan satu sisipan. Jadi, mengingat array yang cukup besar, itu akan gagal.
patrox
72

Kami dapat memperbarui jawaban GTF untuk memperbarui cap waktu dengan mudah

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

Perbarui: untuk menyederhanakan tanggal kita dapat menggunakan karbon seperti yang disarankan @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);

UPDATE2: untuk laravel 5, gunakan updated_atsebagai gantimodified_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);
Eslam Salem Mahmoud
sumber
42
Atau gunakan Karbon di awal script untuk menentukan $nowvariabel: $now = Carbon::now('utc')->toDateTimeString();. Kemudian gunakan saja 'created_at' => $now, 'updated_at' => $nowuntuk setiap penyisipan.
Pedro Moreira
2
Bagaimana kita bisa mendapatkan semua ID dari baris yang baru dimasukkan?
akshaykumar6
2
Kenapa 'utc'? Apakah itu preferensi proyek, atau, apakah fasih selalu bekerja di 'utc'?
pilat
6
Saya tidak ingin memulai argumen "spasi vs. tab" yang besar, tapi tolong, simpan cap waktu di UTC! Ini akan menghemat banyak rasa sakit di kemudian hari! Pikirkan tentang pengguna secara global :)
iSS
2
Jika saya bertanya, apa kebutuhan besar Carbondalam situasi ini? Ada apa dengan ini date("Y-m-d H:i:s")?
Ifedi Okonkwo
30

Bagi siapa pun yang membaca ini, periksa createMany()metode .

/**
 * 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;
}
Alex
sumber
28
Ini bukan apa yang disebut sisipan massal. Karena implementasi yang buruk, fungsi ini akan mempersiapkan dan mengeksekusi permintaan yang sama sekali per Item.
Paul Spiegel
Perlu dicatat ini adalah metode hubungan, tidak bisa dipanggil langsung dari model yaitu Model::createMany().
gali
24

Ini adalah bagaimana Anda melakukannya dengan cara yang lebih fasih,

    $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);
imal hasaranga perera
sumber
3

Saya mencari berkali-kali untuk itu, akhirnya menggunakan custom timestampsseperti di bawah ini:

$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],
    ..................................
]);
srmilon
sumber
2

Eloquent::insert adalah solusi yang tepat tetapi tidak akan memperbarui cap waktu, sehingga Anda dapat melakukan sesuatu seperti di bawah ini

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

Idenya adalah menambahkan Created_at dan updated_at pada seluruh array sebelum melakukan insert

sumit
sumber
0

Dari Laravel 5.7 dengan Illuminate\Database\Query\BuilderAnda dapat menggunakan metode 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));
Walid Natat
sumber
-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));

UserSubscriptionadalah nama model saya. Ini akan mengembalikan "true" jika berhasil memasukkan "false".

Nikunj K.
sumber
-1

Mungkin cara yang lebih Laravel untuk memecahkan masalah ini adalah dengan menggunakan koleksi dan loop itu memasukkan dengan model mengambil keuntungan dari cap waktu.

<?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);
        });
    }
}

EDIT:

Maaf atas kesalahpahaman saya. Untuk memasukkan secara massal ini bisa membantu dan mungkin dengan ini Anda dapat membuat seeder yang baik dan sedikit mengoptimalkannya.

<?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);
    }
}
Francisco Daniel
sumber
1
Ini membuat satu permintaan per item. Ini bukan penyisipan massal.
Emile Bergeron
1
@ EmileBergeron Saya setuju dengan Anda. Saya telah mengedit posting saya jadi mungkin ini bisa membantu untuk memasukkan massal yang baik. Mempertimbangkan meninggalkan tugas yang menghabiskan banyak waktu di luar lingkaran (karbon, bcrypt) ini dapat menghemat banyak waktu Anda.
Francisco Daniel
-1

Untuk penyisipan hubungan kategori, saya menemukan masalah yang sama dan tidak tahu, kecuali bahwa dalam model fasih saya, saya menggunakan Self () untuk memiliki instance dari kelas yang sama di muka untuk merekam beberapa menyimpan dan mengambil id.

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

tanpa "$ obj = new Self ()" itu hanya menyimpan satu catatan (ketika $ obj adalah $ this)

justnajm
sumber
-4

Masalah terpecahkan ... Ubah tabel untuk dimigrasi

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

Larutan:

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();
});
Alexandre Possebon
sumber