how to transform incremental update data into structured table in snowflake - snowflake-cloud-data-platform

I have the following incremental transactional data coming from S3 AVRO format.
{
"after": {
"COM_PCT": null,
"DEPT_ID": 30,
"EMAIL": "AKHOO",
"EMPLOYEE_ID": 115,
"FIRST_NAME": "ALEX",
"LAST_NAME": "TIM",
"HIRE": "1995-05-18 00:00:00",
"MANAGER_ID": 114
},
"before": {},
"current_ts": "2018-05-18 00:00:00:00",
"op_ts": "2018-05-18 00:00:00:00",
"op_type": "I",
"pos": "00000000001123",
"primary_keys": ["EMPLOYEE_ID"],
"table": "HR.EMPLOYEE"
},
{
"after": {
"COM_PCT": null,
"DEPT_ID": 11,
"EMAIL": "AKHOO",
"EMPLOYEE_ID": 115,
"FIRST_NAME": "ALEX",
"LAST_NAME": "TIM",
"HIRE": "1995-05-18 00:00:00",
"MANAGER_ID": 114
},
"before": {},
"current_ts": "2018-05-19 00:00:00:00",
"op_ts": "2018-05-19 00:00:00:00",
"op_type": "U",
"pos": "00000000001124",
"primary_keys": ["EMPLOYEE_ID"],
"table": "HR.EMPLOYEE"
},
{
"after": {
"COM_PCT": null,
"DEPT_ID": 30,
"EMAIL": "AKHOO",
"EMPLOYEE_ID": 115,
"FIRST_NAME": "ALEX",
"LAST_NAME": "TIM",
"HIRE": "1995-05-18 00:00:00",
"MANAGER_ID": 114
},
"before": {},
"current_ts": "2018-05-20 00:00:00:00",
"op_ts": "2018-05-20 00:00:00:00",
"op_type": "U",
"pos": "00000000001125",
"primary_keys": ["EMPLOYEE_ID"],
"table": "HR.EMPLOYEE"
}
The first transaction is an insert transaction for the same primary key,
second two are Update transactions,
I cannot use stream pipe to handle incremental updates, is there a way to convert this into structured table and show only the latest insert/update transaction for that primary key ?

I assumed that the file contains changes only for one table, if not then you need to filter the changes only for a specific table. I also assumed that the data is in the variant type in the table, but this has no effect on the solution how you extract the data.
I suggest this solution:
At the very beginning, you should use the QUALIFY function and filter the data down to the last version of the record only.
Then you can perform a MERGE operation to insert or update the record.
If your data also allows DELETE operations, then they should be included in the code.
Sample data:
CREATE OR REPLACE TABLE SAMPLE_RAW (samples variant);
INSERT INTO SAMPLE_RAW
SELECT parse_json('{
"after": {
"COM_PCT": null,
"DEPT_ID": 30,
"EMAIL": "AKHOO",
"EMPLOYEE_ID": 115,
"FIRST_NAME": "ALEX",
"LAST_NAME": "TIM",
"HIRE": "1995-05-18 00:00:00",
"MANAGER_ID": 114
},
"before": {},
"current_ts": "2018-05-18 00:00:00:00",
"op_ts": "2018-05-18 00:00:00:00",
"op_type": "I",
"pos": "00000000001123",
"primary_keys": ["EMPLOYEE_ID"],
"table": "HR.EMPLOYEE"
}')
UNION ALL
SELECT parse_json('{
"after": {
"COM_PCT": null,
"DEPT_ID": 11,
"EMAIL": "AKHOO",
"EMPLOYEE_ID": 115,
"FIRST_NAME": "ALEX",
"LAST_NAME": "TIM",
"HIRE": "1995-05-18 00:00:00",
"MANAGER_ID": 114
},
"before": {},
"current_ts": "2018-05-19 00:00:00:00",
"op_ts": "2018-05-19 00:00:00:00",
"op_type": "U",
"pos": "00000000001124",
"primary_keys": ["EMPLOYEE_ID"],
"table": "HR.EMPLOYEE"
}')
UNION ALL
SELECT parse_json('{
"after": {
"COM_PCT": null,
"DEPT_ID": 30,
"EMAIL": "AKHOO",
"EMPLOYEE_ID": 115,
"FIRST_NAME": "ALEX",
"LAST_NAME": "TIM",
"HIRE": "1995-05-18 00:00:00",
"MANAGER_ID": 114
},
"before": {},
"current_ts": "2018-05-20 00:00:00:00",
"op_ts": "2018-05-20 00:00:00:00",
"op_type": "U",
"pos": "00000000001125",
"primary_keys": ["EMPLOYEE_ID"],
"table": "HR.EMPLOYEE"
}');
Solution:
WITH src AS (
SELECT TO_TIMESTAMP(s.samples:op_ts::string, 'YYYY-MM-DD HH24:MI:SS:FF') AS op_ts
, s.samples:op_type::string AS op_type
, s.samples:after:COM_PCT::string AS COM_PCT
, s.samples:after:DEPT_ID As DEPT_ID
, s.samples:after:EMAIL::string As EMAIL
, s.samples:after:EMPLOYEE_ID As EMPLOYEE_ID
, s.samples:after:FIRST_NAME::string As FIRST_NAME
, s.samples:after:LAST_NAME::string AS LAST_NAME
, TO_TIMESTAMP(s.samples:after:HIRE::string, 'YYYY-MM-DD HH24:MI:SS') As HIRE
, s.samples:after:MANAGER_ID AS MANAGER_ID
FROM SAMPLE_RAW AS s
QUALIFY ROW_NUMBER() OVER(PARTITION BY EMPLOYEE_ID ORDER BY op_ts DESC) = 1
)
MERGE INTO HR.EMPLOYEE AS trg USING src ON trg.EMPLOYEE_ID = src.EMPLOYEE_ID
WHEN MATCHED AND src.op_type = 'U' THEN UPDATE SET trg.EMAIL = src.EMAIL ...
WHEN MATCHED AND src.op_type = 'D' THEN DELETE
WHEN NOT MATCHED THEN INSERT (EMAIL, FIRST_NAME, LAST_NAME, ...) VALUES (src.EMAIL, src.FIRST_NAME, src.LAST_NAME, ...)
Reference: QUALIFY, MERGE

Related

How to display a column data in a react_table when the column data is array of object?

I am using s react table to to display a table of data
In tags column I want display both the tags present in tags array
of object like this. I did tried some ways but didn't get any
success as of yet. New to tables, so any better way to do this
will be appreciated.
code-sandbox link :
CodeSandBox
[
{
"id": 1,
"first_name": "Torie",
"last_name": "Rustman",
"email": "trustman0#amazon.co.uk",
"date_of_birth": "1979-11-16T23:04:32Z",
"age": 45,
"tags": null,
"phone": "6844103517"
},
{
"id": 2,
"first_name": "Kordula",
"last_name": "Gecks",
"email": "kgecks1#deviantart.com",
"date_of_birth": "1997-08-06T21:07:34Z",
"age": 30,
"tags": null,
"phone": "8429683893"
},
{
"id": 3,
"first_name": "Vikki",
"last_name": "Simoens",
"email": "vsimoens2#ted.com",
"date_of_birth": "2016-04-28T16:59:19Z",
"age": 48,
"tags": [
{ "id": 0, "name": "tag1" },
{ "id": 1, "name": "tag2" }
],
"phone": "8672773997"
},
{
"id": 4,
"first_name": "Burnaby",
"last_name": "Cowern",
"email": "bcowern3#forbes.com",
"date_of_birth": "2017-10-25T08:05:50Z",
"age": 54,
"tags": [
{ "id": 0, "name": "tag3" },
{ "id": 1, "name": "tag4" }
],
"phone": "4257971694"
},
{
"id": 5,
"first_name": "Teddie",
"last_name": "Traice",
"email": "ttraice4#zdnet.com",
"date_of_birth": "2015-04-20T11:45:34Z",
"age": 57,
"tags": [
{ "id": 0, "name": "tag5" },
{ "id": 1, "name": "tag6" }
],
"phone": "3932158370"
},
{
"id": 7,
"first_name": "Shayna",
"last_name": "Dimitresco",
"email": "sdimitresco6#uiuc.edu",
"date_of_birth": "1997-10-28T11:25:07Z",
"age": 21,
"tags": null,
"phone": "1216713219"
}
]
You could define the cell display function when you are defining the columns like you are doing for the date field.
{
Header: "Tags",
Footer: "Tags",
accessor: "tags",
// accessor: "tags[0].name"
Cell: ({ value }) => {
const values = value ? value.map((v) => v.name + ' ') : '';
return values;
}
}
Forked sandbox here

How to extract data from nested Json in Jmeter using Json Extractor

{"data": {"callOrders": [{
"promotionId": null,
"Promotion": null,
"Lines": [
{
"id": 5105808,
"quantity": 10,
"skuId": 769,
"callId": 494285,
"skuBatchId": 733,
"amountDetails": {
"rate": 197.53,
"grossAmount": 2232.089,
"netAmount": 2232.089,
"taxAmount": 256.789,
"taxableAmount": 1975.3,
"subTotal": 1975.3,
"billDiscount": 0,
"tradeDiscount": 0,
"discountAmount": 0,
"promotionDiscount": 0,
"topUpDiscount": 0,
"__typename": "AmountDetail"
},
"rateDetails": {
"rlp": 197.53,
"rlpWithVat": 223.2089,
"netPrice": 197.53,
"netPriceWithVat": 223.2089,
"__typename": "RateDetail"
},
"SKU": {
"id": 769,
"title": "H&S 2in1 Active Protect 180 ml x 24 [82302894]",
"__typename": "SKU"
},
"SKUBatch": {
"priceDetails": {
"rlp": 197.53,
"dlp": 186.35,
"vatPercentage": 0.13,
"mrpSrp": 250,
"mrpStatus": true,
"__typename": "SKUPrice"
},
"batchDetails": {
"batchNumber": "DEFAULT_BATCH",
"__typename": "SKUBatch"
},
"usageDate": {
"manufacture": "0000-00-00",
"expiry": "0000-00-00",
"__typename": "SKUUsage"
},
"updatedAt": "2019-11-05",
"active": true,
"__typename": "SKUBatchRate"
},
"Promotion": {
"id": null,
"title": null,
"type": null,
"scope": null,
"criteria": null,
"__typename": "Promotion"
},
"promotionId": null,
"distributorId": 16,
"__typename": "Line",
"inStock": "INSTOCK",
"freeSku": false,
"focusedSku": false
},
{
"id": 5105809,
"quantity": 50,
"skuId": 95,
"callId": 494285,
"skuBatchId": 111,
"amountDetails": {
"rate": 56.89,
"grossAmount": 3214.2852,
"netAmount": 3214.285,
"taxAmount": 369.785,
"taxableAmount": 2844.5,
"subTotal": 2844.5,
"billDiscount": 0,
"tradeDiscount": 0,
"discountAmount": 0,
"promotionDiscount": 0,
"topUpDiscount": 0,
"__typename": "AmountDetail"
},
"rateDetails": {
"rlp": 56.89,
"rlpWithVat": 64.2857,
"netPrice": 56.89,
"netPriceWithVat": 64.2857,
"__typename": "RateDetail"
},
"SKU": {
"id": 95,
"title": "Whisper Choice 6s x 96 [82252488]",
"__typename": "SKU"
},
"SKUBatch": {
"priceDetails": {
"rlp": 56.89,
"dlp": 53.67,
"vatPercentage": 0.13,
"mrpSrp": 72,
"mrpStatus": true,
"__typename": "SKUPrice"
},
"batchDetails": {
"batchNumber": "DEFAULT_BATCH",
"__typename": "SKUBatch"
},
"usageDate": {
"manufacture": "0000-00-00",
"expiry": "0000-00-00",
"__typename": "SKUUsage"
},
"updatedAt": "2016-08-15",
"active": true,
"__typename": "SKUBatchRate"
},
"Promotion": {
"id": null,
"title": null,
"type": null,
"scope": null,
"criteria": null,
"__typename": "Promotion"
},
"promotionId": null,
"distributorId": 16,
"__typename": "Line",
"inStock": "INSTOCK",
"freeSku": false,
"focusedSku": false
},
{
"id": 5105810,
"quantity": 10,
"skuId": 82,
"callId": 494285,
"skuBatchId": 551,
"amountDetails": {
"rate": 281.88,
"grossAmount": 3185.244,
"netAmount": 3185.244,
"taxAmount": 366.444,
"taxableAmount": 2818.8,
"subTotal": 2818.8,
"billDiscount": 0,
"tradeDiscount": 0,
"discountAmount": 0,
"promotionDiscount": 0,
"topUpDiscount": 0,
"__typename": "AmountDetail"
},
"rateDetails": {
"rlp": 281.88,
"rlpWithVat": 318.5244,
"netPrice": 281.88,
"netPriceWithVat": 318.5244,
"__typename": "RateDetail"
},
"SKU": {
"id": 82,
"title": "Ariel Oxyblu 1 kg x 24 [82250306]",
"__typename": "SKU"
},
"SKUBatch": {
"priceDetails": {
"rlp": 281.88,
"dlp": 268.45,
"vatPercentage": 0.13,
"mrpSrp": 344,
"mrpStatus": true,
"__typename": "SKUPrice"
},
"batchDetails": {
"batchNumber": "DEFAULT_BATCH",
"__typename": "SKUBatch"
},
"usageDate": {
"manufacture": "0000-00-00",
"expiry": "0000-00-00",
"__typename": "SKUUsage"
},
"updatedAt": "2018-01-31",
"active": true,
"__typename": "SKUBatchRate"
},
"Promotion": {
"id": null,
"title": null,
"type": null,
"scope": null,
"criteria": null,
"__typename": "Promotion"
},
"promotionId": null,
"distributorId": 16,
"__typename": "Line",
"inStock": "INSTOCK",
"freeSku": false,
"focusedSku": false
}
],
"__typename": "PromotionOrder"
}]}}
Using $..Lines..id I am getting this
[
5105808,
769,
null,
5105809,
95,
null,
5105810,
82,
null
]
But I want to get value [ 5105808, 5105809, 5105810] only. What should be the way to achieve it?
This is a possible solution:
$..[?(#.skuId)].id
This gets elements that have the skuId attribute and extracts the id attribute.
You're using .. which is a deep scan operator which means that you're looking for all id attribute values no matter where they're located in the JSON.
If you want to get only id of the attributes which are direct children of the Lines object - you need to amend your query to look like: $..Lines[*].id
Demo:
More information: JMeter's JSON Path Extractor Plugin - Advanced Usage Scenarios

How to join Json response element

I am making a call to the OpenWeatherApi am facing a dilemma. I am pulling the response, but only need specific data elements. I am successfully pulling certain elements, but am having trouble pulling the CITY element.
This is the response from the API call:
{
"coord": {
"lon": -122.4,
"lat": 45.64
},
"weather": [
{
"id": 800,
"main": "Clear",
"description": "clear sky",
"icon": "01n"
}
],
"base": "stations",
"main": {
"temp": 287.5,
"pressure": 1022,
"humidity": 82,
"temp_min": 284.25,
"temp_max": 289.25
},
"visibility": 16093,
"wind": {
"speed": 0.96,
"deg": 10.5029
},
"clouds": {
"all": 1
},
"dt": 1537854780,
"sys": {
"type": 1,
"id": 2321,
"message": 0.0172,
"country": "US",
"sunrise": 1537884050,
"sunset": 1537927234
},
"id": 420040945,
"name": "Vancouver",
"cod": 200
}
This is my mapping for the specific elements I need:
const main = response.data["main"]
const sys = response.data["sys"]
const city = response.data.name;
const weather = response.data["weather"][0]
const data = Object.assign(main, weather, sys, city)
res.send(data)
console.log(data)
Finally, this is the response from my mapping:
{
"0": "C",
"1": "i",
"2": "n",
"3": "c",
"4": "i",
"5": "n",
"6": "n",
"7": "a",
"8": "t",
"9": "i",
"temp": 293.74,
"pressure": 1018,
"humidity": 90,
"temp_min": 293.15,
"temp_max": 294.25,
"id": 2179,
"main": "Rain",
"description": "light rain",
"icon": "10n",
"type": 1,
"message": 0.0044,
"country": "US",
"sunrise": 1537874932,
"sunset": 1537918192
}
As you can see, CITY is split up into separate elements. If I only pull CITY, it pulls the accurate City just fine, as
"Cincinnati"
not
"name": "Cincinnati".
How can I join the elements for form the city, or recreate the "name": "City" element altogether?
you are getting wrong result because city is an array and its getting spread. change your code to below code
Object.assign({}, main, weather, sys, {city})
or
Object.assign({}, main, weather, sys, {name:city})
Solution is to convert array value to object property.

ValueFilter does not work in 2sxc in visual query

I have a JSON result set which is like this
"Default": [
{
"PortalId": 0,
"Price": 990000,
"Featured": false,
"Type": 1,
"Bathrooms": 6,
"Rooms": 5,
"Volume": 0,
"Area": 430,
"CreatedDate": "2017-03-13T18:16:08.38Z",
"ShowFrom": "2017-03-13T18:16:08.38Z",
"ShowTill": "9999-12-31T23:59:59.997Z",
"UserId": 2,
"Kitchen": 1,
"CityId": 46,
"Code": "CA-799",
"Verified": false,
"Plot": 1234,
"CityName": "Capdepera",
"ImageName": "RV5",
"ImagePath": "/Portals/0/RealEstateThumbs/20/RV5.jpg",
"Id": 20,
"Guid": "00000000-0000-0000-0000-000000000000",
"Title": null,
"Modified": "0001-01-01T00:00:00Z",
"_2sxcEditInformation": {
"entityId": 20,
"title": "(no title)",
"isPublished": true
}
},
{
"PortalId": 0,
"Price": 1750000,
"Featured": false,
"Type": 1,
"Bathrooms": 6,
"Rooms": 5,
"Volume": 0,
"Area": 360,
"CreatedDate": "2017-03-10T10:25:42.647Z",
"ShowFrom": "2017-03-10T10:25:42.647Z",
"ShowTill": "9999-12-31T23:59:59.997Z",
"UserId": 2,
"Kitchen": 1,
"CityId": 61,
"Code": "ES-9337",
"Verified": false,
"Plot": 1234,
"CityName": "Esporles",
"ImageName": "RV6",
"ImagePath": "/Portals/0/RealEstateThumbs/21/RV6.JPG",
"Id": 21,
"Guid": "00000000-0000-0000-0000-000000000000",
"Title": null,
"Modified": "0001-01-01T00:00:00Z",
"_2sxcEditInformation": {
"entityId": 21,
"title": "(no title)",
"isPublished": true
}
}
When I add a ValueFilter to the Visual Query with a test parameter: [QueryString: Code]=SP
It does not filter on this Code value (in above example, those two results should not be returned).
What am I doing wrong?
The ValueFilter itself is defined as:
Attribute = Code
Value = [QueryString: Value]
Operator: begins
Take: all
It is the key to my solution.
I believe the space in the token [QueryString: Code] is your problem - don't use spaces in tokens.

Group Laravel collection by the given key

in Laravel I want to change response if same user array have multiple response
I get a response with this function
controller.php
public function index(){
$reports = Report::all();
return $this->sendResponse($reports->toArray(), 'User Reports successfully.');
}
This is my response
{
"success": true,
"data": [
{
"id": 66,
"cuid": 20,
"name": "my1",
"created_at": "2018-03-09 00:00:00",
"updated_at": "2018-03-09 00:00:00",
"time": "07:19 PM",
"status": "D"
},
{
"id": 65,
"cuid": 20,
"name": "my1",
"created_at": "2018-03-07 00:00:00",
"updated_at": "2018-03-07 00:00:00",
"time": "07:39 PM",
"status": "D"
},
{
"id": 64,
"cuid": 21,
"name": "my2",
"created_at": "2018-03-02 00:00:00",
"updated_at": "2018-03-05 00:00:00",
"time": "07:01 PM",
"status": "D"
},
{
"id": 63,
"cuid": 20,
"name": "my2",
"created_at": "2018-03-02 00:00:00",
"updated_at": "2018-03-02 00:00:00",
"time": "06:44 PM",
"status": "D"
}
],
"message": "User Reportsssss successfully."
}
This is fine my problem is i have 4 array with 2 user insted showing that way i want to show like this
{
"success": true,
"data": [
my1:{
{
"id": 66,
"cuid": 20,
"name": "my1",
"created_at": "2018-03-09 00:00:00",
"updated_at": "2018-03-09 00:00:00",
"time": "07:19 PM",
"status": "D"
}
{
"id": 65,
"cuid": 20,
"name": "my1",
"created_at": "2018-03-07 00:00:00",
"updated_at": "2018-03-07 00:00:00",
"time": "07:39 PM",
"status": "D"
}
},
my2:{
{
"id": 63,
"cuid": 21,
"name": "my2",
"created_at": "2018-03-07 00:00:00",
"updated_at": "2018-03-07 00:00:00",
"time": "07:39 PM",
"status": "D"
}
{
"id": 64,
"cuid": 21,
"name": "my2",
"created_at": "2018-03-02 00:00:00",
"updated_at": "2018-03-05 00:00:00",
"time": "07:01 PM",
"status": "D"
}
}
],
"message": "User Reportsssss successfully."
}
How to achive this if same user comes under single array
The ideal way to do this would be by using collection pipelines. Your original controller method would become the following;
public function index(){
$reports = Report::all();
return $this->sendResponse($reports->groupBy('name')->toArray(), 'User Reports successfully.');
}
The groupBy method will split the collection results out into other collections, grouped by the provided column. Because the toArray() method cascades, you'll get a nice array back.
You need to loop through the result and modify it as per your requirement.I have tested the below code its working fine. Try using it.
$reports = $reports->toArray();
$finalArray = [];
foreach($reports as $key=>$value) {
$name = $value['name'];
$finalArray[$name][] = $value;
}
return $this->sendResponse($finalArray, 'User Reports successfully.');
Thanks.

Resources