首页 > 解决方案 > 用 Laravel 比较 2 个表格行

问题描述

我正在尝试使用 Laravel Eloquent 模型比较数据库中的 2 行。

我有一个模型History,它每小时运行一次,并将新发现的数据插入到表中history

有时 2 行上的数据可能完全相同,我希望能够在模型中确定 2 行是否相同或它们有差异。

差异实际上可能只是 1 列,但我需要知道差异,所以我知道是否向客户发送电子邮件。

我知道我可以通过选择最新的和之前的行并单独比较所有列来做到这一点,但我真的不想这样做,所以我不知道是否有不同的方法可以做到这一点或者我是否必须手动执行此操作并检查每一列。

我还看到了一种名为isDirty.

我不知道是否可以选择最新的然后传入前一行数据?

将来可能会添加列,这就是我想要自动化它的原因。

这是我拥有的当前方法/模型:

class History extends Model
{
    public function hasIndescrepencies()
    {
       $current = $this->query()->orderBy('updated_at', 'DESC')->first();
        $previous = $this->query()->where('id', '<', $current->id)->orderBy('updated_at', 'DESC')->first();
    }
}

标签: phplaravellumen

解决方案


鉴于您只想在一个模型上比较该表中的currentprevious行,这就是我将如何解决这个问题:

<?php

class History extends Model
{
    public function hasIndescrepencies(): bool
    {
        $current = $this->query()->orderBy('updated_at', 'DESC')->first();
        $previous = null;
        if ($current) {
            $previous = $this->query()->orderBy('updated_at', 'DESC')->where('id', '!=', $current->id)->first();
        }

        if ($current && $previous) {

            $current = $current->toArray();
            $previous = $previous->toArray();

            $ignoreColumns = array_flip(['id', 'created_at', 'updated_at']);

            $currentDataKeys = array_filter(array_keys($current), function($key) use($ignoreColumns) {
                return !array_key_exists($key, $ignoreColumns);
            });

            $currentData = [];
            foreach ($currentDataKeys as $currentDataKey) {
                $currentData[$currentDataKey] = $current[$currentDataKey];
            }

            $previousDataKeys = array_filter(array_keys($previous), function($key) use($ignoreColumns) {
                return !array_key_exists($key, $ignoreColumns);
            });

            $previousData = [];
            foreach ($previousDataKeys as $previousDataKey) {
                $previousData[$previousDataKey] = $previous[$previousDataKey];
            }

            return !empty(array_diff($currentData, $previousData))

        }

        return false;
    }
}

解释:

  1. 您加载最近更新的行,然后以与当前相同的方式选择前一行,同时排除当前行的 id。
  2. 如果存在第一行和第二行,则继续进行检查。此表可能仅从一行开始,也可能根本没有行。
  3. 然后为当前行和上一行获取 key => value 值对(不包括某些列,如 id、created_at 和 updated_at - 因为即使基础行数据可能没有改变,这些也会有所不同)
  4. 然后比较数组 diff 看看是否存在

以下是我确认它使用纯 php 数组工作的方式:

$current = [
    'id' => 1,
    'name' => 'bob',
    'age' => 21,
    'created_at' => '2019-01-01 00:00:00',
    'updated_at' => '2019-01-02 00:00:00',
];

$previous = [
    'id' => 2,
    'name' => 'bob',
    'age' => 20,
    'created_at' => '2019-01-03 00:00:00',
    'updated_at' => '2019-01-04 00:00:00',
];

$ignoreColumns = array_flip(['id', 'created_at', 'updated_at']);

$currentDataKeys = array_filter(array_keys($current), function($key) use($ignoreColumns) {
    return !array_key_exists($key, $ignoreColumns);
});

$currentData = [];
foreach ($currentDataKeys as $currentDataKey) {
    $currentData[$currentDataKey] = $current[$currentDataKey];
}

$previousDataKeys = array_filter(array_keys($previous), function($key) use($ignoreColumns) {
    return !array_key_exists($key, $ignoreColumns);
});

$previousData = [];
foreach ($previousDataKeys as $previousDataKey) {
    $previousData[$previousDataKey] = $previous[$previousDataKey];
}

var_dump(array_diff($currentData, $previousData));

var_dump 的结果应该如下所示:

array(1) {
  ["age"]=>
  int(21)
}

这是正确的,因为唯一不同于当前和以前的是年龄键的值。

希望这可以帮助。


推荐阅读