Correctly return column as JSON Array in MySQL after using CONCAT, GROUP_CONCAT and JSON_OBJECT

I'm using MySQL in a Node.JS API, so I need to get data from the database as JSON objects/arrays.

I'm trying to get a JSON Array nested within the result JSON as one of the values, so this is my current query:

    SELECT
        l.id AS id, l.description AS description, l.parent AS parent,

        (
             SELECT CONCAT(
                 '[',
                 GROUP_CONCAT(
                     JSON_OBJECT(
                     'id', a.id, 'description', a.description,
                     'ip', a.ip, 'lastmovementdetected', a.lastmovementdetected
                     )
                 ),
                 ']'
                 )
              FROM airconditioners AS a WHERE location = l.id
         ) AS airconditioners        

    FROM locations as l`

However, this is the query result (actual output is an array of these JSON objects):

{
        "id": 1,
        "description": "Meu quarto",
        "parent": 0,
        "airconditioners": "[{\"id\": 1, \"ip\": \"192.168.137.96\", \"description\": \"Ar-condicionado\", \"lastmovementdetected\": null},{\"id\": 2, \"ip\": \"192.168.0.1\", \"description\": \"Ar-condicionado\", \"lastmovementdetected\": null},{\"id\": 3, \"ip\": \"192.168.0.1\", \"description\": \"Ar-condicionado\", \"lastmovementdetected\": null}]"
}

SQL is returning the JSON Array as a String and it's also escaping the double quotes from within the JSON.

This is the expected return:

"id": 1,
"description": "Meu quarto",
"parent": 0,
"airconditioners": [
    {
        "id":1,
        "ip":"192.168.137.96",
        "description":"Ar-condicionado",
        "lastmovementdetected":null
    },
    {
        "id":2,
        "ip":"192.168.0.1",
        "description":"Ar-condicionado",
        "lastmovementdetected":null
    },
    {
        "id":3,
        "ip":"192.168.0.1",
        "description":"Ar-condicionado",
        "lastmovementdetected":null
    }
]

Can this be done using a SQL query only? Or I'll have to treat the result before sending the response on the API?

I've tried surrounding the column with a CAST((SELECT...) AS JSON) AS airconditioners and also putting JSON_UNQUOTE() in many places, with no success whatsoever.

EDIT

I couldn't get to a conclusion whether MySQL is compatible with what I want or not. But, for instance, I'm using the following Javascript code to work around it:

Object.keys(result).forEach(key => {
    let airconditioners = result[key].airconditioners;

    if(airconditioners == null) {
    // If the airconditioner field is null, then we replace it with an empty array
        result[key].airconditioners = [];
    } else {
        result[key].airconditioners = JSON.parse(airconditioners);
    }
});

Upvotes: 1

Views: 1122

Answers (1)

youngchill
youngchill

Reputation: 11

use JSON_EXTRACT then get result as you expect

SELECT
        l.id AS id, l.description AS description, l.parent AS parent,

        (
             SELECT JSON_EXTRACT( IFNULL(
                CONCAT(
                 '[',
                 GROUP_CONCAT(
                     JSON_OBJECT(
                     'id', a.id, 'description', a.description,
                     'ip', a.ip, 'lastmovementdetected', a.lastmovementdetected
                     )
                 ),
                 ']'
                 )
             ,'[]'),'$')
              FROM airconditioners AS a WHERE location = l.id
         ) AS airconditioners        

    FROM locations as l`

Upvotes: 1

Related Questions