Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to arrange JSON collections within SQL Server result

I’ve been trying for a while now to retrieve the following result from an SQL Server query:

{
  "data":[
    {"id":3,"type":1,"job":1},
    {"id":4,"type":2,"job":34},
  ],
  "collections": {
    "jobs":[
      {"key":1,"label":"Fenchurch"},
      {"key":34,"label":"Raggle"}
    ],
    "users":[
      {"id":5,"label":"Bob"},
      {"id":20,"label":"Jeff"}
    ]
  }
}

My closest two attempts have gotten me this:

{
  "data":[
    {"id":3,"type":1,"job":1},
    {"id":4,"type":2,"job":34},
  ],
  "collections":[{
    "jobs":[
      {"key":1,"label":"Fenchurch"},
      {"key":34,"label":"Raggle"}
    ],
    "users":[
      {"id":5,"label":"Bob"},
      {"id":20,"label":"Jeff"}
    ]
  }]
}

Notice "collections":[{ and closing }] it should just be "collections": { }

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I’ve gotten this result with the following SQL:

SELECT 
(
    SELECT
    data = (
        SELECT TOP 2 * 
        FROM Event 
        FOR JSON PATH
    ),
    (
    SELECT 
        (
            SELECT TOP 2 id AS 'key', job_number AS 'label' 
            FROM [Job] 
            ORDER BY job_number DESC 
            FOR JSON PATH
        ) AS 'jobs',
        (
            SELECT TOP 2 id, full_name AS 'label' 
            FROM [User] 
            ORDER BY full_name 
            FOR JSON PATH
        ) AS 'users'
        FOR JSON PATH
    ) AS 'collections'
    FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
) AS 'result'

My other closest attempt was using CONCAT_WS() gave me the following:

{
  "data":[
    {"id":3,"type":1,"job":1},
    {"id":4,"type":2,"job":34},
  ],
  "collections":"
  {
    \"jobs\":[
      {\"key\":1,\"label\":\"Fenchurch\"},
      {\"key\":34,\"label\":\"Raggle\"}
    ]
  },
  {
    \"users\":[
      {\"id\":5,\"label\":\"Bob\"},
      {\"id\":20,\"label\":\"Jeff\"}
    ]
  }"
}

Which enclosed "jobs" and "users" in individual { } rather both being within one set.

The SQL to achieve this is as follows:

SELECT
(
    SELECT
    data = (
        SELECT TOP 2 * 
        FROM Event 
        FOR JSON PATH
    ),
    (
        SELECT CONCAT_WS(',',
            (
                SELECT TOP 2 id AS 'key', job_number AS 'label' 
                FROM [Job] 
                ORDER BY job_number DESC 
                FOR JSON PATH, ROOT('jobs')
            ),
            (
                SELECT TOP 2 id, full_name AS 'label' 
                FROM [User] 
                ORDER BY full_name 
                FOR JSON PATH, ROOT('users')
            )
        )
    ) AS 'collections' FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
) AS 'result'

I started looking at splitting this into multiple queries and then construction my own JSON object, but I wasn’t getting very far so thought it’s about time I call on the help of the community.

An help on this would be greatly appreciated.

Thank you in advance.

>Solution :

You could just add WITHOUT_ARRAY_WRAPPER to the collections subquery, but then you would need to nest it in JSON_QUERY() to prevent double-escaping (because “WITHOUT_ARRAY_WRAPPER` does that).

Instead FOR JSON allows you to specify a nested path, which works well if you have multiple scalar values that you want to combine into a single nested object.

SELECT result = (
    SELECT
      data = (
        SELECT TOP 2 * 
        FROM Event 
        FOR JSON PATH
      ),
      (
        SELECT TOP 2
          j.id AS key,
          j.job_number AS label
        FROM Job j
        ORDER BY
          j.job_number DESC 
        FOR JSON PATH
      ) AS [collections.jobs],
      (
        SELECT TOP 2
          u.id,
          u.full_name AS label
        FROM User u
        ORDER BY
          u.full_name 
        FOR JSON PATH
      ) AS [collections.users]
    FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
);
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading