Json flattening in Snowflake - array, data object - arrays

Fairly new to this but can someone help me?
I have the following JSON:
{
"city": [
{
"city_description": {
"text": {
"st": "capital"
}
},
"city_land": {
"st": {
"st": "Other"
}
},
"city_size": {
"id": [
{
"id": "small"
},
{
"id": "big"
},
{
"id": "moderate"
}
]
},
"city_type": {
"id": [
{
"id": "1"
},
{
"id": "2"
},
{
"id": "3"
}
]
},
"conception_date": {
"st": {
"st": "13051977"
}
},
"mark_row": {
"id": {
"id": "1"
}
}
},
{
"city_description": {
"text": {
"st": "cottage"
}
},
"city_land": {
"st": {
"st": "Other"
}
},
"city_size": {
"id": [
{
"id": "small"
},
{
"id": "big"
},
{
"id": "moderate"
}
]
},
"city_type": {
"id": [
{
"id": "1"
},
{
"id": "2"
},
{
"id": "3"
}
]
},
"conception_date": {
"st": {
"st": "15071999"
}
},
"mark_row": {
"id": {
"id": "2"
}
}
}
],
"country": {
"country_code": {
"coordinates": {
"id": "00111022"
},
"name_of_country": {
"st": "Belarus"
},
"desc": {
"st": "Non-eu"
}
},
"country_identifier": {
"id": {
"id": "99"
}
},
"country_description": {
"st": {
"st": "TBD"
}
},
"country_type": {
"is": [
{
"is": "01"
},
{
"is": "X90"
}
]
},
"country_id": {
"si": {
"si": "3"
}
}
}
}
This is stored in snowflake as a string.
I am able to select the data (eg. first column) for the first array.
I am able to select the data (eg. first column) for the first array:
SELECT
f.VALUE:city_description:text:st AS city_description
FROM tableinsnowflake t,
LATERAL flatten(input => t.PARSED_DATA, path => 'city') f
I want to do the same for COUNTRY but seem somehow stuck. Any thoughts? Thanks!

The country could be accessed directly from parsed_data column without using FLATTEN:
SELECT
f.VALUE:city_description:text:st::TEXT AS city_description,
t.parsed_data:country:country_code:name_of_country:st::TEXT AS name_of_country
FROM tab t,
LATERAL FLATTEN(input => t.PARSED_DATA, path => 'city') f

Related

Normalize the Multiple document to single document in MongoDB

{
"_id": "null",
"data": [
{
"name": "abc",
"id": "123"
},
{
"name": "xzy",
"id": "123"
}
]
}
Explanation: the name value will become an object name. also want to convert it into one single document, that contains all the objects. abc and xyz is dynamically coming as a parameter.
Expected Output.
{
"data": {
"abc": {
"name": "abc",
"id": "100"
},
"xyz": {
"name": "xzy",
"id": "123"
}
}
}
Try this:
db.testCollection.aggregate([
{
$project: {
"array": {
$map: {
input: "$data",
as: "item",
in: {
k: "$$item.name",
v: {
"name": "$$item.id",
"id": "$$item.name"
}
}
}
}
}
},
{ $unwind: "$array" },
{
$group: {
_id: "$null",
"data": { $push: "$array" }
}
},
{
$project: {
"data": { $arrayToObject: "$data" }
}
}
]);

Jolt transfer elements from child array to parent

Here i was trying merge elements from 2 child arrays in to its parent one and leave the other one and move the second array to two levels up.
Is there a way to change value on condition, like in the input below,
parties.party.sno ="1" , can this updated as parties..sno='Y'
input:
{
"Parties": [
{
"party": {
"partyId": "100005767",
"sno": 1,
"fn": "Th1mas",
"ln": "Edison",
"emails": [
{
"emailAddress": "jkjk#ui.com"
}
],
"addresses": [
{
"zip": ""
}
],
"shealth": [
{
"stcd": "TN",
"lno": "1"
}
]
},
"seq": {
"typeCd": "1"
}
}
]
}
Expected output:
{
"person": {
"first_name": "Th1mas",
"middle_initial": "Edison",
"last_name": "",
"email_address": "jkjk#ui.com",
"pinCode": ""
},
"shealth": {
"statecd": "ON"
},
//this is the seq no from party.sno
"primary": "Y",
"typeCd": "1"
}
tried spec like this:
[
{
"operation": "shift",
"spec": {
"Parties": {
"*": {
"party": {
"emails": {
"*": {
"emailAddress": "[&1].email_address",
"#(2,fn)": "[&1].first_name",
"#(2,ln)": "[&1].last_name"
}
},
"addresses": {
"*": {
"zip": "[&1].pinCode"
}
},
"shealth": {
"*": {
"stcd": "[&1].statecd"
}
}
}
}
}
}
}
]
This spec works,
"party": {
"sno": {
"1": {
"#Y": "primary"
}
},
Try applying the condition from the current level,
[
{
"operation": "shift",
"spec": {
"Parties": {
"*": {
"party": {
"sno": {
"1": {
"#Y": "primary"
}
},
"emails": {
"*": {
"emailAddress": "person.email_address",
"#(2,fn)": "person.first_name",
"#(2,ln)": "person.last_name"
}
},
"addresses": {
"*": {
"zip": "person.pinCode"
}
},
"shealth": {
"*": {
"stcd": "shealth.statecd"
}
}
},
"seq": {
"typeCd": "typeCd"
}
}
}
}
}
]

Filter data of an array in setState in reactjs

In the code below, I am trying to make an array and remove duplicates from array with reactjs:
The array called names is set in state:
this.state = {
names = []
}
How can I remove the duplicated names and place them into the array
const data = [
{
"obj": {
"no": "1",
"info": [
{
"name": "maya"
},
{
"name": "mina"
}
]
}
},
{
"obj": {
"no": "2",
"info": [
{
"name": "maya"
}
]
}
},
{
"obj": {
"no": "3",
"info": [
{
"name": "mina"
},
{
"name": "Mike"
}
]
}
}
]
data.map((elem) => {
for(let i = 0 ; i < elem.info.length;i++){
let name_info = elem.info[i].name
this.setState({
names: [...this.state.names, name_info]
})
}
})
expected output :["maya","mina",Mike]
If you're fan of one line
[...(new Set(data.map(d => d['obj']['info']).flat().map(info => info['name'])))]
Step by step explanation:
First map takes the input returns only info part of each entry:
data.map(d => d['obj']['info']) yields array of array containing info.
[[{ name: "maya" }, { name: "mina" }], [{ name: "maya" }], [{ name: "mina" }, { name: "Mike" }]]
flat() takes the input from previous map which is the array of array and yields array of elements, so it becomes
[{ name: "maya" }, { name: "mina" }, { name: "maya" }, { name: "mina" }, { name: "Mike" }]
map() takes the input from previous flat which is array of object (which contains name) and returns array of name value.
So you got [ "maya", "mina", "maya", "mina", "Mike" ]
The final array is given to Set, by definition set cannot contain same element more than one. Set of previous array is [ "maya", "mina", "Mike" ].
As final step, set is converted to the array by using spread operator.
const data = [
{
"obj": {
"no": "1",
"info": [
{
"name": "maya"
},
{
"name": "mina"
}
]
}
},
{
"obj": {
"no": "2",
"info": [
{
"name": "maya"
}
]
}
},
{
"obj": {
"no": "3",
"info": [
{
"name": "mina"
},
{
"name": "Mike"
}
]
}
}
];
let names = [];
data.forEach(item => {
Object.values(item)[0].info.forEach(person => {
if(names.indexOf(person.name) === -1)
{
names.push(person.name)
}
})
})
console.log(names);
I think this can help you
First, this is a helper function to get just the unique value of an array
function onlyUnique(value, index, self) {
return self.indexOf(value) === index;
}
And, this is how can get the result you want
const newNames = data.map((elem) => elem.obj.info.map(info => info.name)).flat().filter(onlyUnique)
You can then use it like this
this.setState({
names: [...this.state.names, ...newNames]
})
const data = [{
"obj": {
"no": "1",
"info": [{
"name": "maya"
}, {
"name": "mina"
}]
}
}, {
"obj": {
"no": "2",
"info": [{
"name": "maya"
}]
}
}, {
"obj": {
"no": "3",
"info": [{
"name": "mina"
}, {
"name": "Mike"
}]
}
}]
const names = data.flatMap(obj => obj.obj.info.map(info => info.name));
const unique = names.filter((name, i) => names.indexOf(name) === i);
console.log(unique);

How to delete objects from array

I want to remove object from array if they dont have a value
i have the API A, that returns to me this JSON:
{
"code": 0,
"data": [
{
"name": {
"value": "Ana"
},
"fruit": {
"value": "Grape"
},
"from": {
"value": "BR"
}
},
{
"name": {
"value": "Michael"
},
"fruit": {
"value": "Apple"
},
"from": {
"value": "US"
}
}
]
}
and with the API B, i can return the id for this user passing her the name
i have this code:
getData() {
this.myService.getDataAPI_A()
.subscribe((res) => {
this.myList = res['data'];
if (this.myList) {
for (const key of this.myList) {
this.getId(key.name.value);
}
}
});
}
getId(name) {
this.myService.getDataAPI_B(name) // api B returns id with the name
.subscribe((res) => {
this.myList.map((tempList) => {
if (res.name === tempList.name.value) {
tempList.userId = res.id; // creating a key and setting value
return tempList;
}
return tempList;
});
});
}
then i got this json:
{
"code": 0,
"custodyBovespa": [
{
"name": {
"value": "Ana"
},
"userId": "43",
"fruit": {
"value": "Grape"
},
"from": {
"value": "BR"
}
},
{
"name": {
"value": "Michael"
},
"fruit": {
"value": "Apple"
},
"from": {
"value": "US"
}
}
]
}
Michael does not existe in my data base, so the api returns to me null,
and for some reason dont create the key in my json (why?).
after this i want to remove the object that dont have userId
how i can do this?
If you'd like your resultant array to contain only objects that contain the property userId, you can simply use plain JavaScript .filter.
In my below example, I am removing any element that does not have a "userId" prop.
var data = [
{
"name": {
"value": "Ana"
},
"userId": "43",
"fruit": {
"value": "Grape"
},
"from": {
"value": "BR"
}
},
{
"name": {
"value": "Michael"
},
"fruit": {
"value": "Apple"
},
"from": {
"value": "US"
}
}
];
var dataFiltered = data.filter(val => val["userId"]);
console.log(dataFiltered);
As you said:
Michael does not existe in my data base
and the condition you set is
if (res.name === tempList.name.value) {
tempList.userId = res.id; // creating a key and setting value
return tempList;
}
return tempList;
As the your database doesn't have the the value 'Michael', The above condition is false. So, it gets out of the if clause and just return what it is without userId.
Now if you want to set the 'Michael' userId to null.
if (res.name === tempList.name.value) {
tempList.userId = res.id; // creating a key and setting value
} else {
tempList.userId = null;
}
return tempList;
Then filter out the data's using like #Rich answered.
console.log(data.filter(val => val['userId'] !== null);

Make the sum of booleans as integers with MongoDB

I'm trying to sum booleans (where true means 1 and false -1) in an array for each document in my collection and then sort it.
I'm using MongoDB aggregation pipeline with $addFields, $sum and $cond.
Here's the playground : https://play.db-ai.co/m/XQLKqbkkgAABTFVm
The pipeline :
[
{
"$addFields": {
"score": {
"$sum": {
"$cond": [
"$votes.value",
1,
-1
]
}
}
}
},
{
"$sort": {
"score": -1
}
}
]
The collection :
[
{
"votes": [
{
"value": true
},
{
"value": true
},
{
"value": true
},
{
"value": false
}
]
},
{
"votes": [
{
"value": true
},
{
"value": true
},
{
"value": false
},
{
"value": false
}
]
}
]
Actual results :
[
{
"_id": ObjectId("000000000000000000000000"),
"votes": [
{
"value": true
},
{
"value": true
},
{
"value": true
},
{
"value": false
}
],
"score": 1
},
{
"_id": ObjectId("000000000000000000000001"),
"votes": [
{
"value": true
},
{
"value": true
},
{
"value": false
},
{
"value": false
}
],
"score": 1
}
]
What I want :
[{
"_id": ObjectId("000000000000000000000000"),
"votes": [
{
"value": true
},
{
"value": true
},
{
"value": true
},
{
"value": false
}
],
"score": 2
}, {
"_id": ObjectId("000000000000000000000001"),
"votes": [
{
"value": true
},
{
"value": true
},
{
"value": false
},
{
"value": false
}
],
"score": 0
}]
I got it to work by unwinding the array and then grouping by _id again.
See Playground: https://play.db-ai.co/m/XQMFlZAtYAABLHtL
[
{
"$unwind": {
"path": "$votes"
}
},
{
"$group": {
"_id": "$_id",
"votes": {
"$push": "$votes"
},
"score": {
"$sum": {
"$cond": [
"$votes.value",
1,
-1
]
}
}
}
},
{
"$sort": {
"score": -1
}
}
]
To solve my problem I used $map multiple times. The solution of #Plancke is working but I had issues using a $match afterwards (it was always giving no results).
[
{
$addFields: {
scoresInBoolean: {
$map: {
input: '$votes',
as: 'vote',
in: '$$vote.value',
},
},
},
}, {
$addFields: {
scoresInInteger: {
$map: {
input: '$scoresInBoolean',
as: 'scoreInBoolean',
in: {
$cond: [
'$$scoreInBoolean',
1,
-1,
],
},
},
},
},
}, {
$addFields: {
score: {
$sum: '$scoresInInteger',
},
},
}
]

Resources