【问题标题】:Swapping array values with Eloquent model IDs用 Eloquent 模型 ID 交换数组值
【发布时间】:2017-03-07 14:42:57
【问题描述】:

我需要创建一个导入方法来获取 CSV 文件并导入数据库中的所有内容。

我已经使用 Laravel 的一个 CSV 插件完成了解析,它完美地为我提供了一大组值设置为:

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

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

但是 - 许多列值是我想设置为单独的表/关系的字符串。例如,一列包含项目制造商的名称,我在数据库中设置了制造商表。

我的问题是 - 浏览导入的 CSV 并将字符串与关系表中的相应 ID 交换以使其与我的数据库设计兼容的简单方法是什么?

可以使导入的行:

[       
    'manufacturer' => 'Dell',
]

进入:

[       
    'manufacturer' => '32',
]

我知道我可以做一个 foreach 循环,将所需值与关系模型中的值进行比较,但我确信有一种更简单、更干净的方法。

【问题讨论】:

  • 您能展示一下您是如何插入数据的吗?
  • 我没有插入任何 atm - 需要先交换数据。基本上,因为我得到了一个数组中的 CSV,它对应于我的项目数据库设计,我将通过 Item::insert($data) 进行批量/块插入。我最大的 CSV 包含 4000 行和 20-30 列,其中大部分将是交换后的 FK ID

标签: php csv laravel-5 laravel-5.3


【解决方案1】:

我认为没有任何“好”的方法可以做到这一点 - 您需要查找“制造商”的每个值 - 问题是,您将运行多少次查询?

您需要在此处考虑从 CSV 文件中导入的行数。

你有几个选择。

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) 在哪里 - 然后重新循环

另一种选择是在循环遍历 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

【讨论】:

  • 我在解决方案 2 中考虑了类似的东西。我有制造商、物品类型等东西的模型......我可以像 $manufacturers = ItemManufacturer::pluck('stuff', '需要'); $categories = ItemCategory::pluck('more', 'stuff');然后对照这些数组检查 CSV 列。这样我只做几个数据库查询。交换完成后,我将留下一个数组,其中包含具有列名的项目+分配的正确值。默认情况下,一些来自 CSV(如价格),其余部分将通过上述循环进行交换。
  • @Skipp yeh,这将是一个足够体面的解决方案 =)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-28
  • 2014-03-04
相关资源
最近更新 更多