【问题标题】:Bulk Insertion in Laravel using eloquent ORM使用 eloquent ORM 在 Laravel 中进行批量插入
【发布时间】:2012-09-24 01:05:49
【问题描述】:

我们如何在 Laravel 中使用 Eloquent ORM 执行批量数据库插入?

我正在处理一个 XML 文档,循环遍历它的元素。我想在 Laravel 中完成这样的事情:

$sXML = download_page('http://remotepage.php&function=getItems&count=100&page=1');
$oXML = new SimpleXMLElement($sXML);
$query = "INSERT INTO tbl_item (first_name, last_name, date_added) VALUES";
foreach($oXML->results->item->item as $oEntry){
    $query .=  "('" . $oEntry->firstname . "', '" . $oEntry->lastname . "', '" . date("Y-m-d H:i:s") . "'),";
}
mysql_query($query);

但我收到以下错误。

SQLSTATE[HY093]:无效参数号:混合命名参数和位置参数。

【问题讨论】:

  • 您的模型有has_many 关系吗?
  • @jonathandey 不,我目前没有任何关系
  • @DavidBarker 我尝试使用 for 循环形成 quesr 字符串。我也尝试过在 laravel 中使用事务。
  • @AramBhusal 你能贴出你的代码吗?我确定我这里有一些代码可以帮助你。

标签: php laravel eloquent


【解决方案1】:

这就是你如何以更雄辩的方式做到这一点,

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

【讨论】:

    【解决方案2】:

    你可以使用Eloquent::insert()

    例如:

    $data = [
        ['name'=>'Coder 1', 'rep'=>'4096'],
        ['name'=>'Coder 2', 'rep'=>'2048'],
        //...
    ];
    
    Coder::insert($data);
    

    【讨论】:

    • 这仍然适用于 Laravel 4 吗?
    • @advait:是的,它仍然适用于 Laravel 4。
    • 值得注意的是,它实际上并没有触及Eloquent。它只是代理对Query\Builder@insert() 方法的调用。没有办法使用 Eloquent 有效地插入多行,也没有提供任何批量插入的方法。
    • @CanVural 我们还应该如何更新/创建时间戳?
    • 这将使用一个插入。所以,给定一个足够大的数组,它就会失败。
    【解决方案3】:

    从带有Illuminate\Database\Query\Builder 的 Laravel 5.7 开始,您可以使用 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));
    

    【讨论】:

      【解决方案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();
      });
      

      【讨论】:

        【解决方案5】:

        对于类别关系插入,我遇到了同样的问题,但我不知道,除了在我的 eloquent 模型中,我使用 Self() 在 foreach 中有一个相同类的实例来记录多个保存和抓取 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();
            }
        }
        

        没有 "$obj = new Self()" 它只保存一条记录(当 $obj 是 $this 时)

        【讨论】:

          【解决方案6】:

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

          这个想法是在插入之前在整个数组上添加 created_at 和 updated_at

          【讨论】:

            【解决方案7】:

            找了好多次,终于用自定义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],
                ..................................
            ]);
            

            【讨论】:

            • 这里最简单的答案。不敢相信这在 Laravel 中这么难做到。
            【解决方案8】:

            也许解决这个问题的更 Laravel 方法是使用一个集合并循环插入模型,利用时间戳。

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

            【讨论】:

            • 这对每个项目进行一次查询。这不是批量插入。
            • @EmileBergeron 我同意你的看法。我已经编辑了我的帖子,所以这可能有助于进行良好的批量插入。考虑让需要大量时间的任务(carbon、bcrypt)退出循环,这可以为您节省大量时间。
            【解决方案9】:

            对于正在阅读本文的人,请查看createMany() method

            /**
             * 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;
            }
            

            【讨论】:

            • 这不是所谓的批量插入。由于糟糕的实现,这个函数将为每个 Item 准备和执行一次相同的查询。
            • 值得注意的是这是一个关系方法,不能直接从模型中调用,即Model::createMany()
            【解决方案10】:

            我们可以更新 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);
            

            【讨论】:

            • 或者在脚本开头使用 Carbon 定义一个$now 变量:$now = Carbon::now('utc')-&gt;toDateTimeString();。然后每次插入都使用'created_at' =&gt; $now, 'updated_at' =&gt; $now
            • 如何获取新插入行的所有ID?
            • 为什么是“UTC”?是项目的偏好,还是 eloquent 总是在 'utc' 中工作?
            • 我不想开始一个巨大的“空格与制表符”争论,但请以 UTC 格式保存时间戳!它会在以后为您节省大量的痛苦!考虑全球用户:)
            • 如果我可能会问,在这种情况下,Carbon 的最大需求是什么? date("Y-m-d H:i:s") 怎么了?
            【解决方案11】:
            $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”。

            【讨论】:

              猜你喜欢
              • 2019-10-24
              • 2019-08-01
              • 2014-04-17
              • 2016-03-16
              • 2011-04-09
              • 2014-11-30
              • 2012-12-10
              • 2022-11-02
              • 1970-01-01
              相关资源
              最近更新 更多