Об'ємне введення в Laravel з використанням красномовного ORM


156

Як ми можемо виконувати масові вставки бази даних у Laravel за допомогою Eloquent ORM?

Я хочу це зробити в Laravel: https://stackoverflow.com/a/10615821/600516, але я отримую таку помилку.

SQLSTATE [HY093]: Недійсний номер параметра: змішані імена та позиційні параметри.


1
Чи є у вас has_manyстосунки з вашими моделями?
PapaSmurf

1
@jonathandey ні, я не маю жодних стосунків на даний момент
phoenixwizard

@DavidBarker Я спробував сформувати рядок питань, використовуючи цикл for. Я також спробував використовувати транзакції в laravel.
Phoenixwizard

@AramBhusal Чи можете ви опублікувати свій код? Я впевнений, що у мене є якийсь код, який допоможе вам.
Девід Баркер

Відповіді:


302

Можна просто використовувати Eloquent::insert().

Наприклад:

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

Coder::insert($data);

2
Це все ще стосується Laravel 4?
авансинг

4
@advait: так, це все ще стосується Laravel 4.
Ola

37
Варто зазначити, що насправді це не торкається Eloquent. Це просто проксі виклику Query\Builder@insert()методу. Немає можливості ефективно вставити кілька рядків з красномовним, а також він не пропонує жодного способу масових вставок.
Jarek Tkaczyk

6
@CanVural, що нам також робити для оновлення / створення часових міток?
Мілан Махарджан

3
Для цього буде використана одна вставка. Тож, враховуючи достатньо великий масив, він вийде з ладу.
патрокс

72

Ми можемо оновити відповідь GTF, щоб легко оновлювати часові позначки

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

Оновлення: щоб спростити дату, ми можемо використовувати вуглець, як запропонував @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: для laravel 5 використовуйте updated_atзамістьmodified_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
Або використовувати вуглець на початку сценарію , щоб визначити $nowзмінну: $now = Carbon::now('utc')->toDateTimeString();. Потім просто використовуйте 'created_at' => $now, 'updated_at' => $nowдля кожної вставки.
Педро Морейра

2
Як ми можемо отримати всі ідентифікатори щойно вставлених рядків?
akshaykumar6

2
Чому 'utc'? Це перевага проекту, чи красномовно завжди працює у "utc"?
пілат

6
Я не хочу запускати величезний аргумент "пробіл проти табуляцій", але будь ласка, зберігайте часові позначки в UTC! Це позбавить вас від величезного болю згодом! Подумайте про користувачів у всьому світі :)
iSS

2
Якщо я можу запитати, у чому полягає велика потреба Carbonв цій ситуації? Що не так date("Y-m-d H:i:s")?
Іфєді Оконкво

30

Хто читає це, ознайомтеся з createMany()методом .

/**
 * 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
Це не те, що називається об'ємною вставкою. Через погану реалізацію ця функція буде готувати та виконувати один і той же запит один раз для елемента.
Пол Шпігель

Варто зазначити, що це метод відносин, його не можна викликати безпосередньо з моделі, тобто Model::createMany().
виведення

24

Ось як ви це робите більш красномовно,

    $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

Я багато разів шукав його, нарешті використовував звичай, timestampsяк показано нижче:

$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 це правильне рішення, але воно не буде оновлювати часові позначки, тому ви можете зробити щось на кшталт нижче

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

Ідея полягає в тому, щоб додати insert_at та updated_at до всього масиву, перш ніж робити вставку


0

З Laravel 5.7 Illuminate\Database\Query\Builderможна використовувати метод 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це моя назва моделі. Це поверне "true", якщо вдало вставити ще "false".


-1

Можливо, більш простим способом вирішити цю проблему є використання колекції та вставлення циклу разом із моделлю, використовуючи часові позначки.

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

Редагувати:

Вибачте за моє непорозуміння. Для масової вставки це може допомогти, і можливо, завдяки цьому ви можете зробити хороші сівалки та трохи їх оптимізувати.

<?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
Це робить один запит на предмет. Це не об'ємна вставка.
Еміль Бержерон

1
@EmileBergeron Я згоден з тобою. Я відредагував свою публікацію, тому, можливо, це може допомогти добре вставити групу. Враховуючи те, що залишити завдання, які забирають багато часу з циклу (карбон, bcrypt), це може заощадити вам багато часу.
Франциско Даніель

-1

Для вставки відносин у категорії я зіткнувся з тією ж проблемою і не мав уявлення, за винятком того, що в моїй красномовній моделі я використовував Self (), щоб мати екземпляр одного класу в foreach для запису декількох збережень і захоплення ідентифікаторів.

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

без "$ obj = new Self ()" він зберігає лише один запис (коли $ obj був $ цей)


-4

Проблема вирішена ... Змініть таблицю для міграції

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

Рішення:

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();
});
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.