我如何将QueryBuilder与JSON一起使用

发布于 2025-01-20 22:14:31 字数 2045 浏览 3 评论 0原文

我只是 querybuilder 的新手,确切地说我不知道​​如何在 where 子句中使用 json 对象。我将不胜感激您的迅速帮助。

"post_id": 1
"post": ""
"author": [{"id": 2, "email": "[email protected]"}, {"id": 3, "email": "[email protected]"}]

"post_id": 2
"post": ""
"author": [{"id": 4, "email": "[email protected]"}, {"id": 9, "email": "[email protected]"}]

我想查询表Post,其中author->id是current_user。我已经尽力了。我已经安装了 composer require scienta/doctrine-json-functions

当我运行它时,我发现

"An exception occurred while executing a query: SQLSTATE[42883]: Undefined function: 7 ERROR:  operator does not exist: json = unknown\nLINE 1: ... w0_ WHERE json_extract_path(w0_.author, $1) = $2 ORDER...\n                                                             ^\nHINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.",

我没有想法了。

private function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
    {
        if (WorkshopSession::class !== $resourceClass || $this->security->isGranted('ROLE_ADMIN') || null === $user = $this->security->getUser()) {
            return;
        }
        
        $rootAlias = $queryBuilder->getRootAliases()[0];
        $queryBuilder->andWhere("JSON_EXTRACT_PATH(o.author, :id) = :current_user");
        $queryBuilder->setParameter('id', 'o.id');
        $queryBuilder->setParameter('current_user', $user->getId());
    
    }

我正在使用 api 平台并使用学说扩展。数据库服务器-postgreSQL

please I am just new to querybuilder and precisely I don't know how to work with json object in a where clause. I would appreciate your swift assistance.

"post_id": 1
"post": ""
"author": [{"id": 2, "email": "[email protected]"}, {"id": 3, "email": "[email protected]"}]

"post_id": 2
"post": ""
"author": [{"id": 4, "email": "[email protected]"}, {"id": 9, "email": "[email protected]"}]

I want to query the table Post where the author->id is current_user. I have tried all I can. I have installed composer require scienta/doctrine-json-functions

When I ran it, I got

"An exception occurred while executing a query: SQLSTATE[42883]: Undefined function: 7 ERROR:  operator does not exist: json = unknown\nLINE 1: ... w0_ WHERE json_extract_path(w0_.author, $1) = $2 ORDER...\n                                                             ^\nHINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.",

I am out of ideas.

private function addWhere(QueryBuilder $queryBuilder, string $resourceClass): void
    {
        if (WorkshopSession::class !== $resourceClass || $this->security->isGranted('ROLE_ADMIN') || null === $user = $this->security->getUser()) {
            return;
        }
        
        $rootAlias = $queryBuilder->getRootAliases()[0];
        $queryBuilder->andWhere("JSON_EXTRACT_PATH(o.author, :id) = :current_user");
        $queryBuilder->setParameter('id', 'o.id');
        $queryBuilder->setParameter('current_user', $user->getId());
    
    }

I am using api-platform and using doctrine extensions. Database Server - postgreSQL

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

最美的太阳 2025-01-27 22:14:31

您需要做的第一件事是将选项切换到JSONB,这将帮助您轻松地穿越JSON树而不将自己放在盒子里。

select * from post where author @> '[{"id": "2"}]'; 

在传统的SQL中运行此功能应该可以工作,然后将其转换为DQL。这可能很棘手,因为没有“@>”在DQL中,您可以利用自定义DQL用户定义的功能。我建议这样做,而不是安装第三方库,该库会在版本控制问题(弃用)中添加一个抽象和复杂性。
如下所示,我们使用功能节点,SQLWalker,Lexer和Parser。

use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Query\AST\Node;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\Lexer;
use function sprintf;

class JsonContains extends FunctionNode
{
    /** @var Node */
    /** @psalm-suppress all */
    private $expr1;

    /** @var Node */
    /** @psalm-suppress all */
    private $expr2;

    public function parse(Parser $parser) : void
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $this->expr1 = $parser->StringPrimary();
        $parser->match(Lexer::T_COMMA);
        $this->expr2 = $parser->StringPrimary();
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);

    }

    public function getSql(SqlWalker $sqlWalker) : string
    {
 
        return sprintf(
            '(%s @> %s)',
            $this->expr1->dispatch($sqlWalker),
            $this->expr2->dispatch($sqlWalker)
        );
    }
}

您已经定义了一个,您可以注册它。 Symfony 5 UP建议使用Doctrine.yaml。您可以按照以下方式进行注册,

dql:
            string_functions:
                JSON_CONTAINS: App\Doctrine\Extension\Functions\DQL\UDF\JsonContains

然后在扩展名中,只需使用它即可。

$queryBuilder->andWhere("JSON_CONTAINS(".$rootAlias .".author, :current_user) = true");
       $queryBuilder->setParameter('current_user', json_encode([['id' => $user->getId()]]));
       

这肯定可能会帮助其他人经历它。

干杯!

First thing you need to do, is to switch option to jsonb that would help you traverse the json tree easily without putting yourself in a box.

select * from post where author @> '[{"id": "2"}]'; 

Running this in your traditional sql should work, then convert this to DQL. This may be tricky as there is no '@>' in DQL but you can take advantage of custom DQL User Defined Function. I recommend doing this instead of installing a third party library that would add a layer of abstraction and complexity with versioning issue (deprecation).
As you can see below, we make use of FunctionNode, SqlWalker, Lexer and Parser.

use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\SqlWalker;
use Doctrine\ORM\Query\AST\Node;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\Lexer;
use function sprintf;

class JsonContains extends FunctionNode
{
    /** @var Node */
    /** @psalm-suppress all */
    private $expr1;

    /** @var Node */
    /** @psalm-suppress all */
    private $expr2;

    public function parse(Parser $parser) : void
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);
        $this->expr1 = $parser->StringPrimary();
        $parser->match(Lexer::T_COMMA);
        $this->expr2 = $parser->StringPrimary();
        $parser->match(Lexer::T_CLOSE_PARENTHESIS);

    }

    public function getSql(SqlWalker $sqlWalker) : string
    {
 
        return sprintf(
            '(%s @> %s)',
            $this->expr1->dispatch($sqlWalker),
            $this->expr2->dispatch($sqlWalker)
        );
    }
}

One you have defined this, you can register it. Symfony 5 up suggests to use doctrine.yaml. You can register it as follows

dql:
            string_functions:
                JSON_CONTAINS: App\Doctrine\Extension\Functions\DQL\UDF\JsonContains

Then in your extensions, you can simply use it.

$queryBuilder->andWhere("JSON_CONTAINS(".$rootAlias .".author, :current_user) = true");
       $queryBuilder->setParameter('current_user', json_encode([['id' => $user->getId()]]));
       

This may definitely help others going through it.

Cheers!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文