我需要创建一个导入CSV文件并导入数据库中所有内容的导入方法。
我已经使用Laravel的一个CSV插件完成了解析,它完美地为我提供了一系列值设置为:
[
'col1_name' => 'col1 value',
'col2_name' => 'col2 value',
'col3_name' => 'col3 value,
'...' => '...'
]
这也很完美,因为所有列名都适合我的模型,这使得数据库插入变得轻而易举。
但是 - 很多列值都是我想要设置为单独的表/关系的字符串。例如,一列包含项目制造商的名称,我在我的数据库中设置了制造商表。
我的问题是 - 通过导入的CSV以及使用关系表中相应ID交换字符串的简单方法是什么,使其与我的数据库设计兼容?
会导致导入行的东西:
[
'manufacturer' => 'Dell',
]
成:
[
'manufacturer' => '32',
]
我知道我可以做一个foreach循环,将所需的值与关系模型中的值进行比较,但我确信这样做更容易,更干净。
答案 0 :(得分:0)
我认为没有任何"很好"这样做的方式 - 您需要查找"制造商"的每个值。 - 问题是,你会运行多少次查询?
您需要在此处考虑的是您将从CSV文件中导入的行数。
你有几个选择。
我假设您无论如何都会循环遍历CSV文件的每一行,然后制作新模型?在这种情况下,您可以在此处添加额外的数据库调用;
$model->manufacturer_id = Manufacturer::whereName($colXValue)->first()->id;
(您显然需要在此处插入自己的支票等以确保制造商存在)
这种方法是相对较小的数据集,但是,如果你要导入很多很多行,它可能会因为很多可能不必要的数据库调用而变得迟钝。
另一个选择是在循环CSV行之前创建所有制造商的本地地图;
$mappedManufacturers = Manufacturer::all()->pluck('id', 'name');
这将使$mappedManufacturers
一系列制造商以name
为关键字,id
作为值。这样,当您构建模型时,您可以这样做;
$model->manufacturer_id = $mappedManufacturers[$colXValue];
这种方法也没问题,除非你有成千上万的制造商!
另一个选择是在循环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