3

我正在寻找一种方法来利用Phalcon Framework中新的PostgreSQL JSON 运算符

一个简单的表格来演示:

CREATE TABLE "user"
(
  id_user serial NOT NULL,
  data json,
  CONSTRAINT pk_user PRIMARY KEY (id_user)
)

和一个运行良好的查询psql

select * from "user" where data->>'email' = 'john@example.com';

然而,当用于Phalcon 模型时:

$users = UserModel::query()
            ->where("data->>'email' = :email:")
            ->bind(['email' => 'john@example.com'])
            ->execute();

它产生语法错误:

ERROR: Syntax error, unexpected token >, near to '>'email' = :email:', when parsing: SELECT [Pht\Cli\Model\UserModel].* FROM [Pht\Cli\Model\UserModel] WHERE data->>'email' = :email:

我猜这与PHQL 解析器无法处理语法有关。但问题仍然存在:如何在 Phalcon 中使用 JSON 查询

我试图将 JSON 语法包装到Db\RawValue中:

$users = UserModel::query()
            ->where(new RawValue("data->>'email' = 'john@example.com'"))
            ->execute();

但它似乎只用于更新/插入:

ERROR: Conditions must be string

我总是可以写一个原始查询,但这显然不是要走的路。Model::find此外,如果在and中有可用的语法也会很好Model::findAll

4

4 回答 4

1

现在你可以使用内置的 postgres 函数json_extract_path_text

UserModel::query()->where("json_extract_path_text(data, 'email') = :email:");
于 2016-03-07T09:57:19.447 回答
0

查看是否有实现该->>运算符的底层函数,并改用它。您可以查找pg_operator; 在那里你会看到识别底层功能。数据类型的不同组合可能有多个条目,因此您必须选择正确的一个。如果需要,您可以加入并继续获取类型名称。oprname->>oprcodeoprleftoprrightpg_type

这会给你一个临时的解决方法。更好的方法是避免尝试在您的框架中解析 SQL,或修复其解析器以处理复杂的运算符。

于 2014-01-14T00:35:51.007 回答
0

在深入研究源代码并阅读论坛后,我发现基于此论坛帖子的一个非常好的解决方法。基本思想是使用自定义数据库函数语法,在执行查询之前捕获并解析一个特殊的虚函数:

UserModel::query()->where("PG_JSON_PATH(\"data->>'email'\") = :email:");

为此,我们需要一个专门的 Postgres 适配器(下面的适配器也使用这个 hack 来潜入子查询,就像在原始帖子中一样):

class Postgresql93 extends \Phalcon\Db\Adapter\Pdo\Postgresql
{
    public function query($sqlStatement, $bindParams = null, $bindTypes = null)
    {
        $sqlStatement = $this->handle93syntax($sqlStatement);
        return parent::query($sqlStatement, $bindParams, $bindTypes);
    }

    private function handle93syntax($sqlStatement)
    {
        $specials = join('|', ['SUB_QUERY', 'PG_JSON_PATH']);
        $pattern = "/($specials)[\\s]*\\([\\s]*\\'(.*)\\'[\\s]*\\)/";

        $sqlStatement = preg_replace_callback(
            $pattern,
            function(array $matches){
                $content = str_replace("''", "'", $matches[2]);
                return $content;
            },
            $sqlStatement
        );

        return $sqlStatement;
    }
}
于 2014-01-18T14:02:13.510 回答
0

根据 Craig 的回答,您可以在 Postgres 上执行此查询以查找您要查找的运算符以及要在查询中使用的等效操作码:例如: SELECT oprcode FROM pg_operator WHERE oprname = '->>';

你会得到很多结果,使用适当的一个。

谢谢,

于 2017-08-24T21:35:32.670 回答