Laravel的查询构建器JSON选择器`field-> key`导致语法错误

Chi*_*per 3 php mysql mariadb laravel laravel-5

所以,我想notifications通过比较某个ID和data列来查询Laravel中的表.data列是这样的:

{
    "Message": "some message",
    "id": 3
}
Run Code Online (Sandbox Code Playgroud)

现在,我需要选择ID等于3的所有通知.以下是我尝试执行此操作的方法:

DB::table('notifications')->where('data->id', '3')->get();
Run Code Online (Sandbox Code Playgroud)

但是这会引发以下错误:

SQLSTATE [42000]:语法错误或访问冲突:1064 SQL语法中有错误; 检查与您的MariaDB服务器版本对应的手册,以便在'>'$附近使用正确的语法."id"'=?' 在第1行(SQL:select*from notificationswhere data- >'$."id"'= 3)

我在这里失去理智,任何人都可以帮助我吗?

sep*_*ehr 7

您的查询没有任何问题.这是你的环境.

问题

Laravel MySqlGrammarfield->key字段名称(在Laravel方面)的符号转换为field->'$.key'样式提取(在MySQL方面):

/**
 * Wrap the given JSON selector.
 *
 * @param  string  $value
 * @return string
 */
protected function wrapJsonSelector($value)
{
    $path = explode('->', $value);

    $field = $this->wrapValue(array_shift($path));

    $path = collect($path)->map(function ($part) {
        return '"'.$part.'"';
    })->implode('.');

    // Here:
    return sprintf('%s->\'$.%s\'', $field, $path);
}
Run Code Online (Sandbox Code Playgroud)

我刚刚确认MariaDB不支持将->提取运算符作为JSON_EXTRACT()函数的别名.但是,相同的查询适用于vanilla MySQL 5.7服务器.

假设这个test表:

?????????????????????????
? id ? payload          ?
?????????????????????????
?  1 ? {"a": 1, "b": 2} ?
?????????????????????????
Run Code Online (Sandbox Code Playgroud)

使用->提取运算符的查询:

SELECT payload->"$.b" FROM test;
Run Code Online (Sandbox Code Playgroud)

对MariaDB 10.2.8失败,同时它对2MySQL 5.7.19服务器产生正确的结果.

解决方案

正确的解决方案取决于您在生产中使用的内容.

替换MariaDB

如果您使用的是MySQL,请在开发环境中将MariaDB替换为MySQL.在自制软件管理的macOS机器上,它很简单:

brew services stop mysql
brew uninstall mariadb
brew install mysql
brew services start mysql
Run Code Online (Sandbox Code Playgroud)

您的数据将保持不变.

重写您的查询

但是,如果您在生产中使用MariaDB,则需要重写查询以使用Elias已经提到的JSON_EXTRACT()函数.正如您所看到的,您需要使用Laravel API更加冗长.

以上查询将是:

SELECT JSON_EXTRACT(payload, "$.b") FROM test;
Run Code Online (Sandbox Code Playgroud)