无法在不中断分块的情况下在Eloquent块中更新

时间:2016-10-31 00:48:44

标签: postgresql laravel eloquent

我需要迭代一定数量的行并根据API调用的结果更新它们:

Item::whereIn('id', $ids)->chunk(5, function ($items) {
    $skus = $chunk->pluck('sku')->toArray();
    $pricing = $this->api->getPrices($skus); // Requires chunks of 5 SKUs.

    foreach ($items as $item) {
        if (!empty($pricing[$item->sku])) {
            $item->price = $pricing[$item->sku];
            $item->save();
        }
    }
});

但是,如果save()调用实际上更改了数据库中的一行,那么下一个项目块将包含上一个块中更改的一些项目。

这会导致错过原始查询结果中的某些项目。我可以通过使用Xdebug监视$skus的内容来看到这一点,它显示后续块获取已更新的SKU($ids的内容是唯一的)。

例如,如果返回了30个项目,那么您将获得6个5个块。如果5个项目有更改导致数据库更新这些行,那么循环实际上只能处理25个项目。

如果我从回调中删除$item->save(),那么它完成处理剩余的块,没有SKU旋转到下一个块。但是,无法完全挽救目的。

如果我更改代码以执行此操作,那么我仍然遇到同样的问题:

Item::whereId($item->id)->update($item->getAttributes());

这是使用PostgreSQL 9.6的Laravel 5.3。

据我所知,MySQL不会发生这种情况,因此它似乎是Postgres的怪癖。

我可以通过添加类型$updates的类var Collection并将$items->save();更改为此来解决此问题:

if ($item->isDirty()) {
    $this->updates->push($item);
}

然后在完成所有块之后,处理更新,例如分块循环的外部

if ($this->updates->count()) {
    foreach ($this->updates as $update) {
        $update->save();
    }
}

如果我有一个特别大的结果集需要处理,那么我可以遇到存储一个非常大的集合的内存问题,直到它到达终点。

为什么我不能在不破坏它的情况下更新块中的记录,我该如何(或者我可以)修复它?

根据要求提供$item的示例内容:

App\Models\Items (22) (
    protected table -> string (5) "items"
    protected guarded -> array (1) [
        string (2) "id"
    ]
    protected connection -> NULL
    protected primaryKey -> string (2) "id"
    protected keyType -> string (3) "int"
    protected perPage -> integer 15
    public incrementing -> bool TRUE
    public timestamps -> bool TRUE
    protected attributes -> array (6) [
        'id' => integer 2
        'sku' => string (9) "GM-705-24"
        'price' => integer 3788
        'quantity' => integer 10
        'created_at' => string (19) "2016-10-11 01:50:45"
        'updated_at' => string (19) "2016-10-11 01:50:45"
    ]
    protected original -> array (6) [
        'id' => integer 2
        'sku' => string (9) "GM-705-24"
        'price' => integer 3788
        'quantity' => integer 10
        'created_at' => string (19) "2016-10-11 01:50:45"
        'updated_at' => string (19) "2016-10-11 01:50:45"
    ]
    protected relations -> array (0)
    protected hidden -> array (0)
    protected visible -> array (0)
    protected appends -> array (0)
    protected fillable -> array (0)
    protected dateFormat -> NULL
    protected casts -> array (0)
    protected touches -> array (0)
    protected observables -> array (0)
    protected with -> array (0)
    public exists -> bool TRUE
    public wasRecentlyCreated -> bool FALSE
)

$pricing的内容示例:

array (3) [
    'GM-705-24' => float 37.88,
    'GM-805-25' => float 25.01,
    'GM-715-26' => float 15.05,
]

0 个答案:

没有答案