我正在努力寻找一种方法来检查数组转换列上现有的 WHERE 约束。
我的 Thread 模型有一个电话号码列表...
class Thread extends Model
{
protected $casts = [
'phone_numbers' => 'array'
];
}
所以我的桌子看起来像
+---------------------------------+
| `phone_numbers` VARCHAR(256) |
+---------------------------------+
| ["+15552345678","+15559876543"] |
| ["+15558675309"] |
+---------------------------------+
为了避免使用相同的电话号码重复线程,我使用
firstOrCreate
:
$phone_numbers = ["+15559876543","+15552345678"];
sort($phone_numbers); // always sort in case numbers are out of order
$thread = Thread::firstOrCreate(['phone_numbers' => $phone_numbers]);
正如您可能已经猜到的,这无法检测到现有记录,因为
phone_numbers
列只是数据库中的一个字符串,遗憾的是 firstToCreate
不够聪明,无法根据模型规则强制转换 $phone_numbers
,所以它不会匹配。
我想我可能只是手动转换
$phone_numbers
:
...
$thread = Thread::firstOrCreate(['phone_numbers' => json_encode($phone_numbers)]);
但这创建了一个转义字符串:
+---------------------------------------+
| `phone_numbers` VARCHAR(256) |
+---------------------------------------+
| ["+15552345678","+15559876543"] |
| ["+15558675309"] |
| "[\"+15552345678\",\"+15559876543\"]" | <-- new row
+---------------------------------------+
有一种方法,它不涉及手动对 json 进行排序。 MySQL 有一些可能令人感兴趣的 json 函数,即
JSON_CONTAINS
和 JSON_OVERLAPS
(最后一个仅在 MySQL 8 上可用)
$phone_numbers = ["+15559876543","+15552345678"];
$thread = Thread::query()
->whereRaw('JSON_CONTAINS(phone_numbers, ?)', [json_encode($phone_numbers)])
->firstOrCreate(
[],
['phone_numbers' => $phone_numbers],
);
您实际上并不需要对
$phone_numbers
进行排序才能使 JSON_CONTAINS()
正常工作。如果您确实希望对 phone_numbers
列进行“排序”,您可能无论如何都想这样做。