ChatGPT解决这个技术问题 Extra ChatGPT

使用 eloquent ORM 在 Laravel 中进行批量插入

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

我正在处理一个 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 你能贴出你的代码吗?我确定我这里有一些代码可以帮助你。

T
Theodore R. Smith

您可以只使用 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 我们还应该如何更新/创建时间戳?
这将使用一个插入。所以,给定一个足够大的数组,它会失败。
d
dwitvliet

我们可以更新 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')->toDateTimeString();。然后每次插入只需使用 'created_at' => $now, 'updated_at' => $now
我们如何获取新插入行的所有 ID?
为什么是“UTC”?是项目的偏好,还是雄辩的总是在“utc”中工作?
我不想开始一个巨大的“空格与制表符”争论,但请以 UTC 格式保存时间戳!它会在以后为您节省大量的痛苦!考虑全球用户:)
如果我可能会问,在这种情况下对 Carbon 的最大需求是什么? date("Y-m-d H:i:s") 有什么问题?
H
Hashim Aziz

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

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

E
Emile Bergeron

对于正在阅读本文的人,请查看 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()中调用。
M
Md. Saidur Rahman Milon

我搜索了很多次,最后使用了自定义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 中很难做到。
s
sumit

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


N
Nikunj K.
$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”。


F
Francisco Daniel

也许解决这个问题的更 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),这可以为您节省大量时间。
W
Walid Natat

从带有 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));

j
justnajm

对于类别关系插入,我遇到了同样的问题并且不知道,除了在我雄辩的模型中,我使用 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 时)


Q
Qiniso

问题已解决... 更改表以进行迁移

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