Laravel,使用 JSON_EXTRACT 和 CONCAT_WS 的搜索查询

Laravel, search query with JSON_EXTRACT and CONCAT_WS

我正在尝试在包含 JSON 个对象的 table 中执行搜索,但我无法弄清楚如何使其与 CONCAT_WS 一起使用以便通过以下方式进行搜索一次多个单词,在本例中,first_name 和姓氏的组合。

当使用单个词(first_name、last_name、电子邮件或 phone)进行搜索时,查询运行良好,但 return first_name 和 last_name 都发送到后端时的任何内容。

Model::whereRaw('
        JSON_EXTRACT(data, "$.start") >= ?
            AND
        JSON_EXTRACT(data, "$.personal") = ?
            AND 
        (
            LOWER(JSON_EXTRACT(data, "$.user.first_name")) LIKE ?
                OR
            LOWER(JSON_EXTRACT(data, "$.user.last_name")) LIKE ?
                OR
            LOWER(JSON_EXTRACT(data, "$.user.email")) LIKE ?
                OR
            LOWER(JSON_EXTRACT(data, "$.user.phone")) LIKE ?
                OR
            CONCAT_WS(" ",LOWER(JSON_EXTRACT(data, "$.user.first_name")),LOWER(JSON_EXTRACT(data, "$.user.last_name"))) LIKE ?
        )
        ', [
            Carbon::now(),
            0,
            '"%' . trim(strtolower($request->searchQuery)) . '%"',
            '"%' . trim(strtolower($request->searchQuery)) . '%"',
            '"%' . trim(strtolower($request->searchQuery)) . '%"',
            '"%' . trim(strtolower($request->searchQuery)) . '%"',
            '"%' . trim(strtolower($request->searchQuery)) . '%"',
        ])
        ->orderByRaw('JSON_EXTRACT(data, "$.start") ASC')
        ->selectRaw('table.*, true AS future')
        ->get();

数据结构:

[
    {
        "id": 1,
        "data": {
            "id": 1,
            "user": {
                "id": 1,
                "email": "email1@email.com",
                "phone": "(000) 000-0000",
                "last_name": "John",
                "first_name": "Snow",
            },
            "start": "2022-03-24 17:00:00",
            "personal": 0
        }
    },
    {
        "id": 2,
        "data": {
            "id": 2,
            "user": {
                "id": 2,
                "email": "email2@email.com",
                "phone": "(000) 000-0000",
                "last_name": "Some",
                "first_name": "Name",
            },
            "start": "2022-03-24 17:00:00",
            "personal": 0
        }
    },
    {
        "id": 3,
        "data": {
            "id": 3,
            "user": {
                "id": 3,
                "email": "email3@email.com",
                "phone": "(000) 000-0000",
                "last_name": "Other",
                "first_name": "Name",
            },
            "start": "2022-03-24 17:00:00",
            "personal": 0
        }
    }
]

您需要编辑

  • CONCAT_WS()替换为CONCAT()
  • JSON_EXTRACT() 的结果上使用 JSON_UNQUOTE(),然后再合并

所以这一行
CONCAT_WS(" ",LOWER(JSON_EXTRACT(data, "$.user.first_name")),LOWER(JSON_EXTRACT(data, "$.user.last_name")))

需要对此进行更改

CONCAT(
  LOWER(JSON_UNQUOTE(JSON_EXTRACT(data,"$.user.first_name"))),
  LOWER(JSON_UNQUOTE(JSON_EXTRACT(data, "$.user.last_name")))
)

理由 问题是由于

  • 使用 trim() 方法删除单词之间的空格,同时用空格连接 firstnamelastname
  • 还有 JSON_EXTRACT() returns 带双引号的值,当你在一个单词上使用 like 时不会引起问题,但是当添加两个单词时,引号将存在于中间,并且条件将是错误的,所以我使用 JSON_UNQUOTE 到 trim 它的引号

因此您将得到以下查询

SELECT * FROM `table_name` WHERE JSON_EXTRACT(data, "$.start") >= '2022-03-24 03:09:08'
            AND
        JSON_EXTRACT(data, "$.personal") = 0
            AND 
        (
            LOWER(JSON_EXTRACT(data, "$.user.first_name")) LIKE "%snowjohn%"
                OR
            LOWER(JSON_EXTRACT(data, "$.user.last_name")) LIKE  "%snowjohn%"
                OR
            LOWER(JSON_EXTRACT(data, "$.user.email")) LIKE  "%snowjohn%"
                OR
            LOWER(JSON_EXTRACT(data, "$.user.phone")) LIKE  "%snowjohn%"
                OR
            CONCAT(LOWER(JSON_UNQUOTE(JSON_EXTRACT(data, "$.user.first_name"))),LOWER(JSON_UNQUOTE(JSON_EXTRACT(data, "$.user.last_name"))))  LIKE  "%snowjohn%"
        );

所以,在 Omar 的帮助下,这就是我的问题的解决方案!

Model::whereRaw('
        JSON_EXTRACT(data, "$.start") >= ?
            AND
        JSON_EXTRACT(data, "$.personal") = ?
            AND 
        (
            LOWER(JSON_EXTRACT(data, "$.user.first_name")) LIKE ?
                OR
            LOWER(JSON_EXTRACT(data, "$.user.last_name")) LIKE ?
                OR
            LOWER(JSON_EXTRACT(data, "$.user.email")) LIKE ?
                OR
            LOWER(JSON_EXTRACT(data, "$.user.phone")) LIKE ?
                OR
            CONCAT_WS(" ",
                LOWER(
                    JSON_UNQUOTE(
                        JSON_EXTRACT(data, "$.user.first_name")
                    )
                ),
                LOWER(
                    JSON_UNQUOTE(
                        JSON_EXTRACT(data, "$.user.last_name")
                    )
                )
            ) LIKE ?
        )
        ', [
            Carbon::now(),
            0,
            '"%' . trim(strtolower($request->searchQuery)) . '%"',
            '"%' . trim(strtolower($request->searchQuery)) . '%"',
            '"%' . trim(strtolower($request->searchQuery)) . '%"',
            '"%' . trim(strtolower($request->searchQuery)) . '%"',
            '%'  . trim(strtolower($request->searchQuery)) . '%',
        ])
        ->orderByRaw('JSON_EXTRACT(data, "$.start") ASC')
        ->selectRaw('table.*, true AS future')
        ->get();