【问题标题】:How to compare and update an Eloquent Collection based on another Collection in Laravel如何比较和更新基于 Laravel 中另一个 Collection 的 Eloquent Collection
【发布时间】:2020-10-10 03:42:21
【问题描述】:

我在 Laravel 中有一个名为 Player 的模型。此播放器数据是从外部 API 中提取的。我正在尝试从外部 API 定期更新此外部数据。外部 API 数据是players 表中应包含的内容的权威来源。

我目前有两个集合,一个是来自数据库的数据,另一个是外部API数据。我根据 API 数据在集合中构建了新的Player 模型。

我现在基本上拥有的是:

Collection $playersInDatabase; // Eloquent Collection of type Player
Collection $playersFromApi; // Collection of type Player

$playersFromApi 数据只是转换为新播放器模型并添加到集合中的 JSON API 数据。

我的问题是我不能只擦除整个players 表,因为我一次只修改表的一个子集。有没有一种有效的方法可以使用 Laravel 来比较这两者?我想将任何新的 Player 模型添加到不存在的数据库中,更新任何具有不同数据的现有 Player 模型,然后还删除 API 数据不再具有但仍在数据库中的任何记录(陈旧记录) .

我能想到的唯一方法是多次迭代集合以完成我想做的事情,我觉得有一种更简单更优雅的方法可以更好地利用框架。

参考这里是players 表的样子。我目前正在使用播种机数据:

【问题讨论】:

  • API 是否返回整个玩家群?
  • @Musa 不,它没有。这里面有派系/氏族。通过 API,您一次可以获得一个“派系”的玩家。我只存储了 6-7 个派系的玩家。从本质上讲,一个派系中的玩家一直在变化。所以我想定期更新我的派系玩家数据。所以这意味着有时新玩家加入(创建新玩家),有时他们离开(删除玩家),有时他们会做一些事情,比如改变他们的名字(更新玩家)。我可以在集合中使用diffAssoc 之类的东西,但感觉很笨拙

标签: php laravel collections eloquent laravel-collection


【解决方案1】:

你可以做这样的事情。无需比较,只需 updateOrCreate() 并在单个 DB 调用中删除任何未为相应派系更新的 id。

// the faction id you are querying from API
$faction_id = ...;

// for storing updated model ids
$updated_ids = [];

foreach ($playersFromApi as $playerFromApi) {

    // update record or create a new one
    $player = Player::updateOrCreate(
        [
            // conditions to meet
            '...' => $playerFromApi['...']
        ],
        [
            // data to update   
            '...' => $playerFromApi['...']
        ]

    );

    // store id of updated model
    $updated_ids[] = $player->id;
}


// delete models not updated
Player::where('faction_id',$faction_id)->whereNotIn('id',$updated_ids)->delete();

【讨论】:

  • 作为 API 中的数据,我在使用 updateOrCreate 时已经将其作为新的 Player 模型传递给它,我可以只传递整个模型还是必须列出每个字段和值就像你在例子中展示的那样?
  • 由于您没有发布任何代码,我不确定我是否理解您的问题。听起来您打算运行updateOrCreate() 两次,这不是必需的。如果您已经在之前的步骤中更新了数据库,那么您只需将其集成到您现有的代码中即可。此外,updateOrCreate() 方法接受数组,而不是模型。如果数组中的所有字段都对应于数据库中的字段,则传递整个数组是没有害处的。如果没有,那么您需要单独列出它们。
  • 太棒了,我的意思是我已经将来自外部 API 的数据放入了 Player 模型中,所以我想知道是否可以传递它,但看起来答案是否定的。我按照您在答案中显示的方式进行了操作,并且对我有用!这比我正在研究的解决方案要容易得多!谢谢
  • 相关的快速侧面问题,我在 Eloquent ORM 文档中没有看到它有没有办法确定是否通过此命令创建或更新了记录?我在想,在这之后,我可能会想对任何“新”玩家做一些额外的事情。
  • 您可以使用多种方法。最直接的就是$player->wasRecentlyCreated,它将返回一个布尔值。但是,根据您的用例,您可能需要查看Eloquent Events。它们可以定义为模型中的Closure,或单独的Observer 类。
猜你喜欢
  • 2018-10-22
  • 2021-09-07
  • 1970-01-01
  • 2022-01-18
  • 2013-09-25
  • 2018-05-22
  • 2017-09-09
  • 1970-01-01
  • 2015-06-20
相关资源
最近更新 更多