用Eloquent模型id交换数组值


Swapping array values with Eloquent model IDs

我需要创建一个import方法,该方法接受CSV文件并导入数据库中的所有内容。

我已经用Laravel的一个CSV插件做了解析,它完美地给了我一个大数组的值设置为:

[
    'col1_name' => 'col1 value',
    'col2_name' => 'col2 value',
    'col3_name' => 'col3 value,
    '...' => '...'
]

这也是完美的,因为所有的列名都符合我的模型,这使得数据库插入变得轻而易举。

然而-很多列值是字符串,我想设置为单独的表/关系。例如,其中一列包含产品制造商的名称,并且我在数据库中设置了制造商表。

我的问题是-什么是简单的方法去通过导入的CSV和交换字符串与相应的ID从关系表,使其与我的数据库设计兼容?

使导入行:

[       
    'manufacturer' => 'Dell',
]

为:

[       
    'manufacturer' => '32',
]

我知道我可以做一个foreach循环比较所需的值与值的关系模型,但我相信有一个更简单,更干净的方法来做到这一点。

我不认为有任何"好"的方法来做到这一点-你需要查找"制造商"的每个值-问题是,你会运行多少查询这样做?

这里需要考虑的是将从CSV文件导入多少行。

你有几个选择。

1)查询1 by 1

我假设你要循环通过CSV文件的每一行,然后做一个新的模型?在这种情况下,可以在这里添加一个额外的数据库调用;

$model->manufacturer_id = Manufacturer::whereName($colXValue)->first()->id;

(您显然需要在这里填写您自己的支票等,以确保制造商存在)

此方法适用于相对较小的数据集,但是,如果您要导入很多很多行,那么它可能会因为大量不必要的数据库调用而变得缓慢。

2)映射所有制造商

另一种选择是在遍历CSV行之前创建所有制造商的本地映射;

$mappedManufacturers = Manufacturer::all()->pluck('id', 'name');

这将使$mappedManufacturers成为一个以name为键,id为值的制造商数组。这样,当您构建模型时,您可以执行;

$model->manufacturer_id = $mappedManufacturers[$colXValue];

这种方法也很好,除非你有成千上万的制造商!

3) Where in - then re-loop

另一种选择是在循环遍历CSV行时建立制造商名称列表,使用1个whereIn查询进入数据库,然后重新循环遍历模型以填充制造商ID。

因此,在CSV的初始循环中,您可以临时设置一个属性来存储制造商的名称,同时将其添加到另一个数组;

$models = collect(); $model->..... = ....; $model->manufacturer = $colXValue; $models->push($colXValue);

然后你会得到一组模型。然后在数据库中查询只出现过的制造商:

$manufacturers = Manufacturer::whereIn('name', $models->lists('manufacturer'))->get()->keyBy('name')->toArray();

这将给你一个制造商数组,以他们的name为键。

然后再次遍历$models集合,使用映射分配正确的制造商id;

$model->manufacturer_id = $manufacturers[$model->manufacturer];

希望这能给你一些如何实现这一目标的想法。我想说的是,解决方案主要取决于您的用例——如果这将是一个繁重的任务——我肯定会将其排队,并尝试使用选项1!: P