How to flatten two json arrays using apache drill - apache-drill

{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
}
I have the above json and i want to flatten both batter and topping arrays.
so i tried doing:
SELECT flatten(topping) as toping,flatten(batters.batter) as bat FROM json.jsonfiles.`batter.json`;
which gives me
org.apache.drill.common.exceptions.UserRemoteException: VALIDATION
ERROR: From line 1, column 43 to line 1, column 49: Table 'batters'
not found SQL Query null [Error Id:
33cf80f2-f283-4401-90ce-c262474e0778 on acer:31010]
How can i solve this? Can we flatten two arrays in a single query?

You need to add table alias and refer it in columns. Below query works for me with sample data you have provided.
SELECT flatten(a.topping) as toping,flatten(a.batters.batter) as bat FROM dfs.tmp.`batter.json` a;

Related

Filtering on nested JSON array: Rest Assured

I am trying to filter my GET response(JSON) based on a value in a nested JSON array. For eg: In the following JSON i want to filter an JSON array and print the names of cakes using Chocolate as batter.
{
"id": "0001",
"type": "donut",
"name": "Choco Blueberry Cake",
"ppu": 0.55,
"batter":[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" }
]
}
I have tried something like:
List<String> chocolateCakeList =jsonPath.getList("findAll{it.batter.type=='chocolate'}.name");
and
List<String> chocolateCakeList =jsonPath.getList("findAll{it.batter.it.type=='chocolate'}.name");
Both return empty Lists.
Problem
First, if you want to use findAll then the object to be axtract must be an array. Your json is object {}, not an array []. Actually, your nested object batter is an array [].
keyword to search is Chocolate, not chocolate. Case-sensitive is applied here.
Solution
-If your whole response is exactly what you posted, then the path to extract is
String name = jsonPath.getString("name")
-If your response has structrure like this.
[
{
"id": "0001",
"type": "donut",
"name": "Choco Blueberry Cake",
"ppu": 0.55,
"batter": [
{
"id": "1001",
"type": "Regular"
},
{
"id": "1002",
"type": "Chocolate"
},
{
"id": "1003",
"type": "Blueberry"
}
]
},
{
"id": "0002",
"type": "donut",
"name": "Choco Blueberry Cake",
"ppu": 0.55,
"batter": [
{
"id": "1001",
"type": "Regular"
},
{
"id": "1002",
"type": "Chocolate 2"
},
{
"id": "1003",
"type": "Blueberry"
}
]
}
]
Then the extraction is
List<String> list = jsonPath.getList("findAll {it.batter.findAll {it.type == 'Chocolate'}}.name");

Printing JSON like console.log prints it in Node.js

Wondering if it's possible to print JSON like Node.js prints it out. If there is some standard module or something to do that.
It has the spacing between keys, and when it's too long it goes onto a new line, etc. The coloring would be a bonus.
JSON.stringify(object, null, 2) pretty prints the JSON, wondering if there is something more hidden in there, or any standards, for doing it like Node.js does. Thank you.
This seems to be achievable by using util.inspect():
const util = require('util');
const testJson = `{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
}`
x = JSON.parse(testJson);
x.x = x;
console.log(util.inspect(x, { colors: true }));
The options object takes a parameter called depth that determines how deep it will recurse. The default value is 2. If I increase it to 3:
console.log(util.inspect(x, { colors: true, depth: 3 }));
I get the following:
To make it recurse indefinitely pass depth: null. The default value seems to be 2 in the node cli as well.

Extracting lines from nested json file using Ubuntu

I have nested json file (each field can have one or more sons) with many lines. Something like this:
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
}
Using Ubuntu (or Unix) I would like to find the first 10 lines that their "batters" field is not empty (i.e. in the line one or more of its sons contain value (not null or "").

Angular2, Typescript,Json

I am going to use angular2 platform to develop an application. I am stuck at one point that "How do I print nested json in Angular2 Component's template".
json file:
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": "0000.55",
"batters":
{
"batter":
[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":
[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
}
It's greatful if someone help me....:)
Try something like this:
<div *ngFor="let obj of jsonData">
<div>{{obj.id}}</div>
...
<div *ngFor="let bat of obj.batters.batter">
<div>{{bat.id}}</div>
<div>{{bat.type}}</div>
</div>
<div *ngFor="let topp of obj.topping">
<div>{{topp.id}}</div>
<div>{{topp.type}}</div>
</div>
</div>
You can change your object:
...,
"batters": [
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
],
...
then you can do like this:
<div *ngFor="let bat of obj.batters">
Hope this will help.

how to create a angular table row to have a collapsed row

I have a table which will have collapsed rows that have 2nd level info, but not all the rows will have this 2nd level data.
How can i write a controller to only show a 2nd level collapse row if the JSON script has a 2nd level?
With the following json defined in your controller:
$scope.cakes = [{ "id": "0001", "type": "donut", "name": "Cake",
"ppu": 0.55, "batters": "whatever",
"topping": [ { "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" } ] },
{ "id": "0002", "type": "cupcake", "name": "Cupcake",
"ppu": 0.60, "batters": "whatever",
"topping": [] },
{ "id": "0003", "type": "muffin", "name": "Muffin",
"ppu": 0.25, "batters": "whatever",
"topping": [] }
];
you can selectively show a second row in a table where cake.topping.length is greater than 0:
<table>
<tr ng-repeat-start="cake in cakes">
<td>{{cake.type}}</td><td>{{cake.name}}</td>
</tr>
<tr ng-repeat-end ng-show="cake.topping.length>0">
<td ng-repeat="t in cake.topping">{{t.type}}</td>
</tr>
</table>