ETL Device Monitoring == :::info this work still in progress (WIP) ::: ## Table dd_device_gobiz_mobile_kong_60d_dinata ## Notes - `bi-gojek.stream.fr_beast_kong_log_proto_01` does not contain device id for `goresto_service`. Therefore it can't get device-level data - This will be used to add universe GoResto device if Clevertap and Kong could not cover it ## To Do - [ ] add merchant device which does not have merchant_id using gobiz user data which has been filtered (only paired to 1 merchant or non admin) ## Design ## Implementation ### SQL Script ```flow WITH _DECLARE AS ( SELECT '2020 DATE_SUB(end_date, INTERVAL 65 day) AS start_date, end_date, DATE_SUB(end_date, INTERVAL 2 day) AS max_partition_date FROM ( SELECT CURRENT_DATE("Asia/Jakarta") AS end_date ) ), _GOBIZ_USER AS ( SELECT DISTINCT gobiz_user_id, phone_normalized AS phone, merchant_id, one_to_one_flag FROM `bi-gojek.spi_reference_gomerchant.dd_device_gobiz_user` ), -- _GOBIZ_USER AS ( -- SELECT -- id AS gobiz_user_id, -- `bi-gojek.spi_playground_gomerchant.function_dinata_normalizePhone`(phone) AS phone, -- merchant_id -- FROM -- `bi-gojek.spi_reference_gomerchant.dd_gojek_hermes_user` -- ), -- Select only GoBiz users that have 1 to 1 relationship with outlet. _GOBIZ_USER_FILTERED AS ( WITH _BASE AS ( SELECT id AS gobiz_user_id, merchant_id, `bi-gojek.spi_playground_gomerchant.function_dinata_normalizePhone`(phone) AS phone FROM `bi-gojek.spi_reference_gomerchant.dd_gojek_hermes_user` WHERE approved IS TRUE AND phone IS NOT NULL ), _EXCLUDE AS ( SELECT phone, COUNT(DISTINCT merchant_id) AS total_outlets, COUNT(DISTINCT gobiz_user_id) AS total_user_id FROM _BASE WHERE phone IS NOT NULL GROUP BY 1 ) SELECT * FROM _BASE WHERE phone NOT IN (SELECT DISTINCT phone FROM _EXCLUDE) ), _CMP AS ( SELECT merchant_id, goresto_restaurant_id FROM `bi-gojek.spi_reference_midtrans.dd_gojek_saudagar_merchant`, _DECLARE WHERE _PARTITIONDATE = DATE_SUB(_DECLARE.end_date, INTERVAL 1 day) ), _RAW_KONG AS ( WITH _RAW_KONG AS ( SELECT time, api_request_uri, gobiz_user_id, app_version, LOWER(device_os_split[offset(0)]) AS os_type, CASE WHEN device_os_split[offset(1)] IS NULL THEN NULL WHEN device_os_split[offset(1)] = '1' THEN '1.0' WHEN device_os_split[offset(1)] = '2' THEN '1.1' WHEN device_os_split[offset(1)] = '3' THEN '1.5' WHEN device_os_split[offset(1)] = '4' THEN '1.6' WHEN device_os_split[offset(1)] = '5' THEN '2.0' WHEN device_os_split[offset(1)] = '8' THEN '2.2' WHEN device_os_split[offset(1)] = '9' THEN '2.3' WHEN device_os_split[offset(1)] = '11' THEN '3.0' WHEN device_os_split[offset(1)] = '14' THEN '4.0' WHEN device_os_split[offset(1)] = '16' THEN '4.1' WHEN device_os_split[offset(1)] = '19' THEN '4.4' WHEN device_os_split[offset(1)] = '21' THEN '5.0' WHEN device_os_split[offset(1)] = '23' THEN '6.0' WHEN device_os_split[offset(1)] = '24' THEN '7.0' WHEN device_os_split[offset(1)] = '26' THEN '8.0' WHEN device_os_split[offset(1)] = '28' THEN '9.0' WHEN device_os_split[offset(1)] = '29' THEN '10.0' WHEN device_os_split[offset(1)] = '30' THEN '11.0' ELSE '9999.0' END AS os_version FROM ( SELECT time, api_request_uri, user_owner_id AS gobiz_user_id, app_version, SPLIT(device_os, ' ') AS device_os_split FROM `bi-gojek.staging_gomerchant.fd_kong_log_goresto_service` _KONG, _DECLARE WHERE time >= TIMESTAMP(_DECLARE.start_date) ) ), _GOFOOD_ORDER AS ( SELECT order_no, _CMP.merchant_id AS merchant_id FROM `bi-gojek.access.sd_gofood_booking` _GF_TRX, _DECLARE LEFT JOIN `bi-gojek.reference.dd_merchant` _GF_MERCHANT ON _GF_TRX.merchant_id = _GF_MERCHANT.id LEFT JOIN _CMP ON _GF_MERCHANT.uuid = _CMP.goresto_restaurant_id WHERE _PARTITIONTIME >= TIMESTAMP(_DECLARE.start_date) ), _RAW_KONG_URI_EXTRACTED AS ( SELECT time, `bi-gojek.spi_playground_gomerchant.function_dinata_extractKongOrderID`(api_request_uri) AS order_no, `bi-gojek.spi_playground_gomerchant.function_dinata_extractKongRestoID`(api_request_uri) AS resto_id, gobiz_user_id, app_version, os_type, os_version FROM _RAW_KONG, _DECLARE WHERE time >= TIMESTAMP(_DECLARE.start_date) ) SELECT _RAW_KONG_URI_EXTRACTED.time, COALESCE(_GOFOOD_ORDER.merchant_id, _CMP.merchant_id, _GOBIZ_USER.merchant_id) AS merchant_id, _RAW_KONG_URI_EXTRACTED.order_no, _RAW_KONG_URI_EXTRACTED.resto_id AS goresto_restaurant_id, _RAW_KONG_URI_EXTRACTED.gobiz_user_id, app_version, os_type, os_version FROM _RAW_KONG_URI_EXTRACTED LEFT JOIN _GOFOOD_ORDER ON _RAW_KONG_URI_EXTRACTED.order_no = _GOFOOD_ORDER.order_no LEFT JOIN _CMP ON _RAW_KONG_URI_EXTRACTED.resto_id = _CMP.goresto_restaurant_id --LEFT JOIN _GOBIZ_USER ON _RAW_KONG_URI_EXTRACTED.gobiz_user_id = CAST(_GOBIZ_USER.gobiz_user_id AS STRING) LEFT JOIN _GOBIZ_USER AS _GOBIZ_USER_ONE_TO_ONE ON _RAW_KONG_URI_EXTRACTED.gobiz_user_id = CAST(_GOBIZ_USER_ONE_TO_ONE.gobiz_user_id AS STRING) AND _GOBIZ_USER_ONE_TO_ONE.one_to_one_flag IS TRUE LEFT JOIN _GOBIZ_USER ON _RAW_KONG_URI_EXTRACTED.gobiz_user_id = CAST(_GOBIZ_USER.gobiz_user_id AS STRING) WHERE _GOFOOD_ORDER.order_no IS NOT NULL ), _BASE_KONG AS ( SELECT NULL AS device_brand_model_std, merchant_id, gobiz_user_id, app_version, os_type, os_version, -- MIN(time) AS min_updated_at, MAX(time) AS max_updated_at, COUNT(*) AS goresto_total_event, SUM(CASE WHEN DATE(time,"Asia/Jakarta") >= DATE_SUB(CURRENT_DATE("Asia/Jakarta"), INTERVAL 7 day) THEN 1 ELSE 0 END) AS goresto_total_event_7days, SUM(CASE WHEN DATE(time,"Asia/Jakarta") >= DATE_SUB(CURRENT_DATE("Asia/Jakarta"), INTERVAL 14 day) THEN 1 ELSE 0 END) AS goresto_total_event_14days, SUM(CASE WHEN DATE(time,"Asia/Jakarta") >= DATE_SUB(CURRENT_DATE("Asia/Jakarta"), INTERVAL 30 day) THEN 1 ELSE 0 END) AS goresto_total_event_30days, SUM(CASE WHEN DATE(time,"Asia/Jakarta") >= DATE_SUB(CURRENT_DATE("Asia/Jakarta"), INTERVAL 60 day) THEN 1 ELSE 0 END) AS goresto_total_event_60days FROM _RAW_KONG, _DECLARE WHERE time >= TIMESTAMP(_DECLARE.start_date) GROUP BY 1,2,3,4,5,6 ), _SUMMARY_KONG AS ( SELECT UPPER(CONCAT(COALESCE(_BASE_KONG.merchant_id, CAST(_BASE_KONG.gobiz_user_id AS STRING)), '.', IFNULL(CAST(device_brand_model_std AS STRING), 'brand_model_null'))) AS device_kong_id, device_brand_model_std, merchant_id, gobiz_user_id, app_version, os_type, os_version, -- MIN(min_updated_at) AS min_updated_at, MAX(max_updated_at) AS max_updated_at, SUM(goresto_total_event) AS goresto_total_event, SUM(goresto_total_event_7days) AS goresto_total_event_7days, SUM(goresto_total_event_14days) AS goresto_total_event_14days, SUM(goresto_total_event_30days) AS goresto_total_event_30days, SUM(goresto_total_event_60days) AS goresto_total_event_60days FROM _BASE_KONG GROUP BY 1,2,3,4,5,6,7 ), ---------------------------------------------------------------------------------------- -- B. GET MAX DEVICE APP VERSION -- This will calculate each merchant product event. ---------------------------------------------------------------------------------------- _MAX_VERSION_DEV_MID_TIMESTAMP AS ( WITH _APP_VERSION AS ( SELECT device_kong_id, merchant_id, app_version, max_updated_at FROM _SUMMARY_KONG ), _MAX_TS AS ( SELECT device_kong_id, merchant_id, MAX(max_updated_at) AS max_updated_at FROM _APP_VERSION GROUP BY 1,2 ), _APP_VERSION_MAX AS ( SELECT DISTINCT _APP_VERSION.device_kong_id, _APP_VERSION.merchant_id, _APP_VERSION.app_version, _APP_VERSION.max_updated_at FROM _APP_VERSION LEFT JOIN _MAX_TS ON _MAX_TS.device_kong_id = _APP_VERSION.device_kong_id AND _MAX_TS.max_updated_at = _APP_VERSION.max_updated_at WHERE _MAX_TS.device_kong_id IS NOT NULL AND _MAX_TS.max_updated_at IS NOT NULL ) SELECT DISTINCT device_kong_id, merchant_id, app_version, CASE WHEN ARRAY_LENGTH(app_version_split) > 0 THEN CAST(app_version_split[OFFSET(0)] AS INT64) ELSE NULL END AS app_version_major, CASE WHEN ARRAY_LENGTH(app_version_split) > 1 THEN CAST(app_version_split[OFFSET(1)] AS INT64) ELSE 0 END AS app_version_minor, CASE WHEN ARRAY_LENGTH(app_version_split) > 2 THEN CAST(app_version_split[OFFSET(2)] AS INT64) ELSE 0 END AS app_version_patch, max_updated_at FROM ( SELECT device_kong_id, merchant_id, app_version, max_updated_at, SPLIT(app_version, '.') AS app_version_split FROM _APP_VERSION_MAX ) _TA ), _SUMMARY_CT_UNION_MAX_VERSION_MAJOR AS ( SELECT device_kong_id, merchant_id, max_updated_at, app_version, app_version_major, app_version_minor, app_version_patch, MAX(app_version_major) OVER (PARTITION BY device_kong_id) AS max_major_device, MAX(app_version_major) OVER (PARTITION BY device_kong_id, merchant_id) AS max_major_device_outlet FROM _MAX_VERSION_DEV_MID_TIMESTAMP ), _SUMMARY_CT_UNION_MAX_VERSION_MINOR AS ( SELECT _TB.*, MAX(CASE WHEN _TB.max_major_device = _TB.app_version_major THEN _TB.app_version_minor ELSE NULL END) OVER (PARTITION BY _TB.device_kong_id) AS max_minor_device, MAX(CASE WHEN _TB.max_major_device_outlet = _TB.app_version_major THEN _TB.app_version_minor ELSE NULL END) OVER (PARTITION BY _TB.device_kong_id, _TB.merchant_id) AS max_minor_device_outlet FROM ( SELECT _TA.* FROM _SUMMARY_CT_UNION_MAX_VERSION_MAJOR _TA ) _TB ), _SUMMARY_CT_UNION_MAX_VERSION_PATCH AS ( SELECT _TB.*, MAX( CASE WHEN _TB.max_major_device = _TB.app_version_major AND _TB.max_minor_device = _TB.app_version_minor THEN _TB.app_version_patch ELSE NULL END ) OVER (PARTITION BY _TB.device_kong_id) AS max_patch_device, MAX( CASE WHEN _TB.max_major_device_outlet = _TB.app_version_major AND _TB.max_minor_device_outlet = _TB.app_version_minor THEN _TB.app_version_patch ELSE NULL END ) OVER (PARTITION BY _TB.device_kong_id, _TB.merchant_id) AS max_patch_device_outlet FROM ( SELECT _TA.* FROM _SUMMARY_CT_UNION_MAX_VERSION_MINOR _TA ) _TB ), _SUMMARY_CT_UNION_MAX_VERSION AS ( SELECT DISTINCT _TA.*, CONCAT(_TA.max_major_device, '.', _TA.max_minor_device, '.', _TA.max_patch_device) AS max_app_version_device, CONCAT(_TA.max_major_device_outlet, '.', _TA.max_minor_device_outlet, '.', _TA.max_patch_device_outlet) AS max_app_version_device_outlet FROM _SUMMARY_CT_UNION_MAX_VERSION_PATCH _TA ), _MAX_VERSION_DEVICE AS ( SELECT DISTINCT device_kong_id, merchant_id, max_updated_at AS max_updated_at_app_version, max_app_version_device, max_app_version_device_outlet, max_major_device AS max_app_version_device_major, max_minor_device AS max_app_version_device_minor, max_patch_device AS max_app_version_device_patch, max_major_device_outlet AS max_app_version_device_outlet_major, max_minor_device_outlet AS max_app_version_device_outlet_minor, max_patch_device_outlet AS max_app_version_device_outlet_patch FROM _SUMMARY_CT_UNION_MAX_VERSION WHERE max_app_version_device_outlet = app_version ), ---------------------------------------------------------------------------------------- -- C. GET MAX DEVICE OS VERSION ---------------------------------------------------------------------------------------- _MAX_OS_VERSION_DEV_MID_TIMESTAMP AS ( WITH _OS_VERSION AS ( SELECT device_kong_id, merchant_id, os_type, os_version, max_updated_at FROM _SUMMARY_KONG ), _MAX_TS AS ( SELECT device_kong_id, merchant_id, MAX(max_updated_at) AS max_updated_at FROM _OS_VERSION GROUP BY 1,2 ), _OS_VERSION_MAX AS ( SELECT DISTINCT _OS_VERSION.device_kong_id, _OS_VERSION.merchant_id, _OS_VERSION.os_type, _OS_VERSION.os_version, _OS_VERSION.max_updated_at FROM _OS_VERSION LEFT JOIN _MAX_TS ON _MAX_TS.device_kong_id = _OS_VERSION.device_kong_id AND _MAX_TS.max_updated_at = _OS_VERSION.max_updated_at WHERE _MAX_TS.device_kong_id IS NOT NULL AND _MAX_TS.max_updated_at IS NOT NULL ) SELECT DISTINCT device_kong_id, merchant_id, os_type, -- This is to standardized into x.x the os_version since some live tracker use x.x.x. -- It will affect with the final logic 'max_os_version_device_outlet = os_version'. CONCAT(os_version_major, '.', os_version_minor) AS os_version, os_version_major, os_version_minor, max_updated_at FROM ( SELECT DISTINCT device_kong_id, merchant_id, os_type, os_version, CASE WHEN ARRAY_LENGTH(os_version_split) > 0 THEN CAST(os_version_split[OFFSET(0)] AS INT64) ELSE NULL END AS os_version_major, CASE WHEN ARRAY_LENGTH(os_version_split) > 1 THEN CAST(os_version_split[OFFSET(1)] AS INT64) ELSE 0 END AS os_version_minor, max_updated_at FROM ( SELECT device_kong_id, merchant_id, os_type, os_version, max_updated_at, SPLIT(os_version, '.') AS os_version_split FROM _OS_VERSION_MAX ) _TA ) _TB ), _SUMMARY_KONG_UNION_MAX_OS_VERSION_MAJOR AS ( SELECT device_kong_id, merchant_id, max_updated_at, os_type, os_version, os_version_major, os_version_minor, MAX(os_version_major) OVER (PARTITION BY device_kong_id) AS max_major_device, MAX(os_version_major) OVER (PARTITION BY device_kong_id, merchant_id) AS max_major_device_outlet FROM _MAX_OS_VERSION_DEV_MID_TIMESTAMP ), _SUMMARY_KONG_UNION_MAX_OS_VERSION_MINOR AS ( SELECT _TB.*, MAX(CASE WHEN _TB.max_major_device = _TB.os_version_major THEN _TB.os_version_minor ELSE NULL END) OVER (PARTITION BY _TB.device_kong_id) AS max_minor_device, MAX(CASE WHEN _TB.max_major_device_outlet = _TB.os_version_major THEN _TB.os_version_minor ELSE NULL END) OVER (PARTITION BY _TB.device_kong_id, _TB.merchant_id) AS max_minor_device_outlet FROM ( SELECT _TA.* FROM _SUMMARY_KONG_UNION_MAX_OS_VERSION_MAJOR _TA ) _TB ), _SUMMARY_KONG_UNION_MAX_OS_VERSION AS ( SELECT DISTINCT _TA.*, CONCAT(_TA.max_major_device, '.', _TA.max_minor_device) AS max_os_version_device, CONCAT(_TA.max_major_device_outlet, '.', _TA.max_minor_device_outlet) AS max_os_version_device_outlet FROM _SUMMARY_KONG_UNION_MAX_OS_VERSION_MINOR _TA ), _MAX_OS_VERSION_DEVICE AS ( SELECT DISTINCT device_kong_id, merchant_id, max_updated_at AS max_updated_at_os_version, os_type, max_os_version_device, max_os_version_device_outlet, max_major_device AS max_os_version_device_major, max_minor_device AS max_os_version_device_minor, max_major_device_outlet AS max_os_version_device_outlet_major, max_minor_device_outlet AS max_os_version_device_outlet_minor FROM _SUMMARY_KONG_UNION_MAX_OS_VERSION WHERE max_os_version_device_outlet = os_version ) SELECT UPPER(_SUMMARY_KONG.device_kong_id) AS device_kong_id, _SUMMARY_KONG.device_brand_model_std, UPPER(_SUMMARY_KONG.merchant_id) AS merchant_id, _SUMMARY_KONG.gobiz_user_id, _MAX_VERSION_DEVICE.max_app_version_device, _MAX_VERSION_DEVICE.max_app_version_device_outlet, _MAX_VERSION_DEVICE.max_app_version_device_major, _MAX_VERSION_DEVICE.max_app_version_device_minor, _MAX_VERSION_DEVICE.max_app_version_device_patch, _MAX_VERSION_DEVICE.max_app_version_device_outlet_major, _MAX_VERSION_DEVICE.max_app_version_device_outlet_minor, _MAX_VERSION_DEVICE.max_app_version_device_outlet_patch, _MAX_OS_VERSION_DEVICE.os_type, _MAX_OS_VERSION_DEVICE.max_os_version_device, _MAX_OS_VERSION_DEVICE.max_os_version_device_outlet, _MAX_OS_VERSION_DEVICE.max_os_version_device_major, _MAX_OS_VERSION_DEVICE.max_os_version_device_minor, _MAX_OS_VERSION_DEVICE.max_os_version_device_outlet_major, _MAX_OS_VERSION_DEVICE.max_os_version_device_outlet_minor, --MIN(_SUMMARY_KONG.min_updated_at) AS min_updated_at, MAX(_SUMMARY_KONG.max_updated_at) AS max_updated_at, IFNULL(SUM(goresto_total_event),0) AS goresto_total_event, IFNULL(SUM(goresto_total_event_7days),0) AS goresto_total_event_7days, IFNULL(SUM(goresto_total_event_14days),0) AS goresto_total_event_14days, IFNULL(SUM(goresto_total_event_30days),0) AS goresto_total_event_30days, IFNULL(SUM(goresto_total_event_60days),0) AS goresto_total_event_60days FROM _SUMMARY_KONG LEFT JOIN _MAX_VERSION_DEVICE ON _SUMMARY_KONG.device_kong_id = _MAX_VERSION_DEVICE.device_kong_id AND _SUMMARY_KONG.merchant_id = _MAX_VERSION_DEVICE.merchant_id LEFT JOIN _MAX_OS_VERSION_DEVICE ON _SUMMARY_KONG.device_kong_id = _MAX_OS_VERSION_DEVICE.device_kong_id AND _SUMMARY_KONG.merchant_id = _MAX_OS_VERSION_DEVICE.merchant_id WHERE _SUMMARY_KONG.merchant_id IS NOT NULL GROUP BY 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 ```