UNNEST массив хранится внутри объекта? - PullRequest
1 голос
/ 18 апреля 2020

Я пытаюсь раскрутить массив, который хранится внутри объекта в BigQuery. Я относительно неопытен, когда дело доходит до JSON, но какое-то время я безуспешно искал решение для этого.

У меня есть другие случаи, подобные этому, где я создал UDF внутри BigQuery для определения структуры JSON массивов и JSON объектов, где они разделены, но это первый случай, с которым я столкнулся, когда один находится внутри другого.

Пример структуры (JSON name такое "маршруты");

{"legs": 

        [{"eta": "2020-04-25T00:00:00.000Z", "etd": "2020-03-31T00:00:00.000Z", "change": "new"}], 

"arrival_time": "2020-04-25T00:00:00.000+00:00", "cut_off_date": "2020-03-29", 
"departure_time": "2020-03-31T00:00:00.000+00:00", "last_pickup_on": "2020-03-29"}

Я пробовал так много разных вещей, что было бы трудно перечислить, поэтому мне интересно, есть ли у кого-нибудь простое решение этого вопроса, которое я мог бы упустить из виду? Я прочитал документацию по BQ и попробовал что-то вроде ...

UNNEST(routes) as routes_unnest

, которое не работает, наряду с сохраненными UDF, которые имеют структуру, подобную приведенной ниже ...

CREATE OR REPLACE FUNCTION `project`.udfs.extract_routes(input STRING)
  RETURNS STRUCT<
    arrival_time TIMESTAMP,
    cut_off_date STRING,
    departure_time TIMESTAMP,
    last_pickup_on STRING,
    legs ARRAY<
    STRUCT<
      eta TIMESTAMP,
      etd TIMESTAMP,
      change STRING,
  LANGUAGE js AS "return JSON.parse(input);";

Я считаю, что моя ошибка лежит в моем запросе, если это так, то я застрял в том, как запросить раздел массива. Помощь очень ценится здесь! Спасибо за ваше время.

1 Ответ

0 голосов
/ 18 апреля 2020

Ниже для BigQuery Standard SQL

#standardSQL
CREATE TEMP FUNCTION json2array(input STRING)
RETURNS ARRAY<STRING>
LANGUAGE js AS '''
  return JSON.parse(input).map(x=>JSON.stringify(x));
'''; 
SELECT 
  JSON_EXTRACT_SCALAR(routes, '$.arrival_time') AS arrival_time,
  JSON_EXTRACT_SCALAR(routes, '$.cut_off_date') AS cut_off_date,
  JSON_EXTRACT_SCALAR(routes, '$.departure_time') AS departure_time,
  JSON_EXTRACT_SCALAR(routes, '$.last_pickup_on') AS last_pickup_on,
  JSON_EXTRACT_SCALAR(leg, '$.eta') eta,
  JSON_EXTRACT_SCALAR(leg, '$.etd') etd,
  JSON_EXTRACT_SCALAR(leg, '$.change') change
FROM `project.dataset.table`,
UNNEST(json2array(JSON_EXTRACT(routes, '$.legs'))) leg

Вы можете проверить, поиграть с выше, используя фиктивные данные, как в примере ниже

#standardSQL
CREATE TEMP FUNCTION json2array(input STRING)
RETURNS ARRAY<STRING>
LANGUAGE js AS '''
  return JSON.parse(input).map(x=>JSON.stringify(x));
'''; 
WITH `project.dataset.table` AS (
SELECT '''
  {"legs": 
  [
    {"eta": "2020-04-25T00:00:00.000Z", "etd": "2020-03-31T00:00:00.000Z", "change": "new"},
    {"eta": "2020-04-25T00:00:00.000Z", "etd": "2020-03-31T00:00:00.000Z", "change": "new1"},
    {"eta": "2020-04-25T00:00:00.000Z", "etd": "2020-03-31T00:00:00.000Z", "change": "new2"}
  ], 
  "arrival_time": "2020-04-25T00:00:00.000+00:00", 
  "cut_off_date": "2020-03-29", 
  "departure_time": "2020-03-31T00:00:00.000+00:00", 
  "last_pickup_on": "2020-03-29"}
''' routes
)
SELECT 
  JSON_EXTRACT_SCALAR(routes, '$.arrival_time') AS arrival_time,
  JSON_EXTRACT_SCALAR(routes, '$.cut_off_date') AS cut_off_date,
  JSON_EXTRACT_SCALAR(routes, '$.departure_time') AS departure_time,
  JSON_EXTRACT_SCALAR(routes, '$.last_pickup_on') AS last_pickup_on,
  JSON_EXTRACT_SCALAR(leg, '$.eta') eta,
  JSON_EXTRACT_SCALAR(leg, '$.etd') etd,
  JSON_EXTRACT_SCALAR(leg, '$.change') change
FROM `project.dataset.table`,
UNNEST(json2array(JSON_EXTRACT(routes, '$.legs'))) leg

с выводом ниже

Row arrival_time                cut_off_date    departure_time          last_pickup_on  eta etd change   
1   2020-04-25T00:00:00.000+00:00   2020-03-29  2020-03-31T00:00:00.000+00:00   2020-03-29  2020-04-25T00:00:00.000Z    2020-03-31T00:00:00.000Z    new  
2   2020-04-25T00:00:00.000+00:00   2020-03-29  2020-03-31T00:00:00.000+00:00   2020-03-29  2020-04-25T00:00:00.000Z    2020-03-31T00:00:00.000Z    new1     
3   2020-04-25T00:00:00.000+00:00   2020-03-29  2020-03-31T00:00:00.000+00:00   2020-03-29  2020-04-25T00:00:00.000Z    2020-03-31T00:00:00.000Z    new2     

Или вы можете заключить запрос в TO_JSON_STRING, если вам нужно выводить все еще как [unnested] JSON

#standardSQL
CREATE TEMP FUNCTION json2array(input STRING)
RETURNS ARRAY<STRING>
LANGUAGE js AS '''
  return JSON.parse(input).map(x=>JSON.stringify(x));
'''; 
SELECT TO_JSON_STRING(t) AS route
FROM (
  SELECT 
    JSON_EXTRACT_SCALAR(routes, '$.arrival_time') AS arrival_time,
    JSON_EXTRACT_SCALAR(routes, '$.cut_off_date') AS cut_off_date,
    JSON_EXTRACT_SCALAR(routes, '$.departure_time') AS departure_time,
    JSON_EXTRACT_SCALAR(routes, '$.last_pickup_on') AS last_pickup_on,
    JSON_EXTRACT_SCALAR(leg, '$.eta') eta,
    JSON_EXTRACT_SCALAR(leg, '$.etd') etd,
    JSON_EXTRACT_SCALAR(leg, '$.change') change
  FROM `project.dataset.table`,
  UNNEST(json2array(JSON_EXTRACT(routes, '$.legs'))) leg
) t   

, в этом случае вывод будет выглядеть как ниже

Row route    
1   {"arrival_time":"2020-04-25T00:00:00.000+00:00","cut_off_date":"2020-03-29","departure_time":"2020-03-31T00:00:00.000+00:00","last_pickup_on":"2020-03-29","eta":"2020-04-25T00:00:00.000Z","etd":"2020-03-31T00:00:00.000Z","change":"new"}     
2   {"arrival_time":"2020-04-25T00:00:00.000+00:00","cut_off_date":"2020-03-29","departure_time":"2020-03-31T00:00:00.000+00:00","last_pickup_on":"2020-03-29","eta":"2020-04-25T00:00:00.000Z","etd":"2020-03-31T00:00:00.000Z","change":"new1"}    
3   {"arrival_time":"2020-04-25T00:00:00.000+00:00","cut_off_date":"2020-03-29","departure_time":"2020-03-31T00:00:00.000+00:00","last_pickup_on":"2020-03-29","eta":"2020-04-25T00:00:00.000Z","etd":"2020-03-31T00:00:00.000Z","change":"new2"}    

Где каждая строка представляет собой JSON, к которому можно легко обратиться с помощью функций JSON_EXTRACT_SCALAR

{
"arrival_time": "2020-04-25T00:00:00.000+00:00",
"cut_off_date": "2020-03-29",
"departure_time": "2020-03-31T00:00:00.000+00:00",
"last_pickup_on": "2020-03-29",
"eta": "2020-04-25T00:00:00.000Z",
"etd": "2020-03-31T00:00:00.000Z",
"change": "new"
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...