Node JS How to build a nested object using parent ids - node.js

for my internship, I need to build a nested object using parent IDs I don't want children attribute array.
I have an array of object with id and parent id and I use npm flatnest to do it. This works for a one-level hierarchy but the code must be adapted for a multi-hierarchy level.
I don't know how to adapt that to multi-hierarchy level.
This is my array of Object
var fn = require("flatnest");
const flat =
[
{ "id": 1, "name": 'Restaurants', 'parentId': 0},
{ "id": 2, "name": 'family restaurant', 'parentId': 1, 'value':'Excellent'},
{ "id": 3, "name": 'Sun restaurant', 'parentId': 1,'value':""},
{ "id": 4, "name": 'Sun restaurant 1', 'parentId': 3, 'value':'Good'},
{ "id": 5, "name": 'Sun restaurant 2', 'parentId': 3, 'value':"bad"},
{ "id": 6, "name": 'Hotels', 'parentId': 0,'value':""},
{ "id": 7, "name": 'Space Hotel', 'parentId': 6,'value':""},
{ "id": 8, "name": 'Sun Hotel', 'parentId': 7,'value':'Nice'},
{ "id": 9, "name": 'Moon Hotel', 'parentId': 7,'value':""},
{ "id": 10, "name": 'Moon Hotel 1', 'parentId': 9, 'value':"Excellent"},
{ "id": 11, "name": 'Moon Hotel 2', 'parentId': 9, 'value':"Worst"},
];
To use nested function of npm flatnest, I have to flat my array of Object (const flat)
My code to flat :
var transform={};
for(var i=0;i<flat.length;i++)
{
if(typeof flat[parseInt(i)+1] !== 'undefined' )
{
if(flat[i].id==flat[i+1].parentId)
{
var t = flat[i].name;
transform[t.concat(".").concat(flat[i+1].name)]=flat[i+1].value;
}else{
transform[t.concat(".").concat(flat[i+1].name)]=flat[i+1].value;
}
}
}
console.log(transform)
var nested = fn.nest(transform)
console.log(nested)
I expect the output of console.log(transform) to be
{ 'Restaurants.family restaurant':'Excellent',
'Restaurants.Sun restaurant.Sun restaurant 1': 'Good',
'Restaurants.Sun restaurant.Sun restaurant 2': 'bad',
'Hotels.Space Hotel.Sun Hotel': 'Nice',
'Hotels.Space Hotel.Moon Hotel.Moon Hotel 1': 'Excellent',
'Hotels.Space Hotel.Moon Hotel.Moon Hotel 2' : 'Worst'}
Then by using nested function :
var nested = fn.nest(transform)
console.log(nested)
The output must be exactly like that :
"Restaurants":{
"family restaurant":"Excellent",
"Sun restaurant":{
"Sun restaurant 1":"Good",
"Sun restaurant 2":"bad"
}
},
"Hotels":{
"Space Hotel":{
"Sun Hotel":"Nice",
"Moon Hotel":{
"Moon Hotel 1":"Excellent",
"Moon Hotel 2":"Worst"
}
}
}
}
but the actual output of console.log(transform) is :
{'Restaurants.family restaurant':'Excellent',
'Restaurant.Sun restaurant':'',
'Sun restaurant.Sun restaurant 1':'Good',
'Sun restaurant.Sun restaurant 2':'bad',
'Sun restaurant.Hotels':'',
'Hotels.Space Hotel':'',
'Space Hotel.Sun Hotel':'Nice'
'Space Hotel.Moon Hotel':'',
'Moon Hotel.Moon Hotel 1':'Excellent',
'Moon Hotel.Moon Hotel 2': 'Worst'}

I'm not using flatnest. But the below code works for me. Please check and let me know if it doesn't work for any scenario.
const flat = [{
"id": 1,
"name": 'Restaurants',
'parentId': 0
},
{
"id": 2,
"name": 'family restaurant',
'parentId': 1,
'value': 'Excellent'
},
{
"id": 3,
"name": 'Sun restaurant',
'parentId': 1,
'value': ""
},
{
"id": 4,
"name": 'Sun restaurant 1',
'parentId': 3,
'value': 'Good'
},
{
"id": 5,
"name": 'Sun restaurant 2',
'parentId': 3,
'value': "bad"
},
{
"id": 6,
"name": 'Hotels',
'parentId': 0,
'value': ""
},
{
"id": 7,
"name": 'Space Hotel',
'parentId': 6,
'value': ""
},
{
"id": 8,
"name": 'Sun Hotel',
'parentId': 7,
'value': 'Nice'
},
{
"id": 9,
"name": 'Moon Hotel',
'parentId': 7,
'value': ""
},
{
"id": 10,
"name": 'Moon Hotel 1',
'parentId': 9,
'value': "Excellent"
},
{
"id": 11,
"name": 'Moon Hotel 2',
'parentId': 9,
'value': "Worst"
},
];
const map = new Map();
const result = flat.reduce((acc, curr) => {
let val = {}
if (curr.parentId == 0)
acc[curr.name] = val;
else {
if (map.get(curr.parentId)) {
if (curr.value != '')
val = curr.value;
map.get(curr.parentId)[curr.name] = val;
}
}
map.set(curr.id, val);
return acc;
}, {});
console.log(JSON.stringify(result));

Related

How to project an item in an array to the top level and also fetch only the matched objects in the array

Currently this is an example of a dataset in my salesOrder collection
{
"totalCost": 4,
"salesOrderRef": "s4",
"customerRef": "c10",
"date": "2021-06-03T00:00:00.000Z",
"etd": "2021-06-24T00:00:00.000Z",
"delivered": true,
"paid": false,
"inventory": [{
"sku": "i3",
"quantity": 1,
"priceEa": 2,
"discount": "0"
}, {
"sku": "i2",
"quantity": 2,
"priceEa": 2,
"discount": 2
}]
}
How do I get it to match
{
"salesOrderRef": "s4",
"customerRef": "c10",
"sku": "i3",
"quantity": 1,
"priceEa": 2,
"discount": "0"
}
if I search sku: i3? If there are any duplicate sku in the inventory array of a single salesOrder document, I would also like it to duplicate another result out, like
{
"salesOrderRef": "s4",
"customerRef": "c10",
"sku": "i3",
"quantity": 1,
"priceEa": 2,
"discount": "0"
},
{
"salesOrderRef": "s4",
"customerRef": "c10",
"sku": "i3",
"quantity": 3,
"priceEa": 4,
"discount": "0"
}
How could I achieve this? I tried using aggregation and filters but I'm not sure how
Try this aggregation query, from what I understood this is should give you the output document you have mentioned.
db.collection.aggregate([
{
$unwind: "$inventory"
}, {
$project: {
"_id" : 0,
"salesOrderRef": 1,
"customerRef": 1,
"sku": "$inventory.sku",
"quantity": "$inventory.quantity",
"priceEa": "$inventory.priceEa",
"discount": "$inventory.discount"
}
}, ])

Node JS add children properties to JSON

I have 2 Json ARRAY listA and listB want to add listB items into listA based on id's issue_id and descendents_parent_issue_id
const listA = [
{
"issue_id": 2,
"name": 'A',
},
{
"issue_id": 1,
"name": 'B',
},
{
"issue_id": 3,
"name": 'C'
},
{
"issue_id": 4,
"name": 'D',
}
];
const listB = [{
"descendents_issue_id": 7,
"descendents_parent_issue_id": 2,
"issue": "Breakdown",
},{
"descendents_issue_id": 881,
"descendents_parent_issue_id": 7,
"issue": "Hydraulic arm failure"
},{
"descendents_issue_id": 8,
"descendents_parent_issue_id": 2,
"descendents_issue": "Setup/ Changeover"
},{
"descendents_issue_id": 942,
"descendents_parent_issue_id": 7,
"descendents_issue": "Pump Overload"
}];
Expected output:
[
{
"issue_id": 2,
"name": "A",
"children": [
{
"descendents_issue_id": 7,
"descendents_parent_issue_id": 2,
"issue": "Breakdown",
"children": [
{
"descendents_issue_id": 881,
"descendents_parent_issue_id": 7,
"issue": "Hydraulic arm failure"
},
{
"descendents_issue_id": 942,
"descendents_parent_issue_id": 7,
"descendents_issue": "Pump Overload"
}
]
},
{
"descendents_issue_id": 8,
"descendents_parent_issue_id": 2,
"descendents_issue": "Setup/ Changeover"
}
]
},
{
"issue_id": 1,
"name": "B"
},
{
"issue_id": 3,
"name": "C"
},
{
"issue_id": 4,
"name": "D"
}
]
tried this following code not getting the expected output
function processIssues(arr, arrayB) {
return arr.reduce((result, item) => {
const itemInB = arrayB.find(itemB => itemB.descendents_parent_issue_id == item.issue_id);
if (itemInB) {
let child = [];
child.push(itemInB);
item.children = child
}
return [...result, item];
}, []);
}
Getting Output
[
{
"issue_id": 2,
"name": "A",
"children": [
{
"descendents_issue_id": 7,
"descendents_parent_issue_id": 2,
"issue": "Breakdown"
}
]
},
{
"issue_id": 1,
"name": "B"
},
{
"issue_id": 3,
"name": "C"
},
{
"issue_id": 4,
"name": "D"
}
]
when I tried recursion getting maximum call stack exceeded. please help
I think you should parse the items for the first array and try to scan the second array matching items with issue_id:
const processIssues = (arr, arrB) => {
let found;
return arr.map(({ issue_id, children = [], ...rest }) => {
found = arrB.find(
({ descendents_parent_issue_id }) =>
descendents_parent_issue_id === issue_id
);
return found
? { issue_id, children: [...children, { ...found }], ...rest }
: { issue_id, ...rest };
});
};

timeUnit does not work after a flatten and flod transformation

Is it possible to use timeUnit after a flatten and flod transformation?
In the example below it doesnt work!
If I remove the timeUnit from the x axis it plots, but without the good things that come with the timeUnit.
Thanks
This is an example code that can be executed in the link below
https://vega.github.io/editor/#/edited
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"description": "Sales in a Year.",
"width": 500,
"height": 200,
"data": {
"values": [
{"timestamp": ["2019-01-01","2019-02-01","2019-03-01","2019-04-01","2019-05-01","2019-06-01",
"2019-07-01","2019-08-01","2019-09-01","2019-10-01","2019-11-01","2019-12-01"],
"cars" : [55, 43, 91, 81, 53, 19, 87, 52, 52, 44, 52, 52],
"bikes" : [12, 6, 2, 0, 0, 0, 0, 0, 0, 3, 9, 15]}
]
},
"transform": [
{"flatten": ["timestamp", "cars", "bikes"]},
{"fold": ["cars", "bikes"]}
],
"mark": {"type":"bar", "tooltip": true, "cornerRadiusEnd": 4},
"encoding": {
"x": {"field": "timestamp",
"timeUnit": "month",
"type": "ordinal",
"title": "",
"axis": {"labelAngle": 0}},
"y": {"field": "value",
"type": "quantitative",
"title": "Soiling Loss"},
"color":{"field": "key",
"type": "nominal"}
}
}
For convenience, strings in input data with a simple temporal encoding are automatically parsed as dates, but such parsing is not applied to data that is the result of a transformation.
In this case, you can do the parsing manually with a calculate transform (view in editor):
{
"$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"description": "Sales in a Year.",
"width": 500,
"height": 200,
"data": {
"values": [
{
"timestamp": [
"2019-01-01",
"2019-02-01",
"2019-03-01",
"2019-04-01",
"2019-05-01",
"2019-06-01",
"2019-07-01",
"2019-08-01",
"2019-09-01",
"2019-10-01",
"2019-11-01",
"2019-12-01"
],
"cars": [55, 43, 91, 81, 53, 19, 87, 52, 52, 44, 52, 52],
"bikes": [12, 6, 2, 0, 0, 0, 0, 0, 0, 3, 9, 15]
}
]
},
"transform": [
{"flatten": ["timestamp", "cars", "bikes"]},
{"fold": ["cars", "bikes"]},
{"calculate": "toDate(datum.timestamp)", "as": "timestamp"}
],
"mark": {"type": "bar", "tooltip": true, "cornerRadiusEnd": 4},
"encoding": {
"x": {
"field": "timestamp",
"timeUnit": "month",
"type": "ordinal",
"title": "",
"axis": {"labelAngle": 0}
},
"y": {"field": "value", "type": "quantitative", "title": "Soiling Loss"},
"color": {"field": "key", "type": "nominal"}
}
}

How to return an array of structs from a struct of arrays in Standard SQL?

I have a non-repeated record column on my table that I want to access.
On this record, there are several repeated values.
So it is a RECORD, like so:
STRUCT<item ARRAY<STRING> unit_cost ARRAY<INT64> quantity ARRAY<INT64>> as costs
Eg. the data might represent:
item ['cheese', 'ham', 'salad']
unit_cost [2, 5, 8]
quantity [1, 2, 1]
So I want to return this as a nicer data structure, an array of structs:
[
{'item': 'cheese', 'unit_cost': 2, 'quantity': 1},
{'item': 'ham', 'unit_cost': 5, 'quantity': 2}
{'item': 'salad', 'unit_cost': 8, 'quantity': 1}
]
I tried:
SELECT ARRAY_AGG(costs)
but it results in
[
{
"item": ['cheese', 'ham', 'salad'],
"unit_cost": [2, 5, 8],
"quantity": [1, 2, 1]
}
]
which is not what I had expected it to return.
Is it possible to go from a STRUCT of multiple ARRAY to an ARRAY of multiple STRUCT using some clever use of Standard SQL here?
Below is for BigQuery Standard SQL
#standardSQL
SELECT
ARRAY(
SELECT AS STRUCT item, unit_cost, quantity
FROM UNNEST(costs.item) item WITH OFFSET
LEFT JOIN UNNEST(costs.unit_cost) unit_cost WITH OFFSET USING(OFFSET)
LEFT JOIN UNNEST(costs.quantity) quantity WITH OFFSET USING(OFFSET)
) AS costs
FROM `project.dataset.table`
if to apply to sample data from your question - result is (in JSON View)
[
{
"costs": [
{
"item": "cheese",
"unit_cost": "2",
"quantity": "1"
},
{
"item": "ham",
"unit_cost": "5",
"quantity": "2"
},
{
"item": "salad",
"unit_cost": "8",
"quantity": "1"
}
]
}
]
You can use below query:
with data as (
select STRUCT<item ARRAY<STRING>, unit_cost ARRAY<INT64>, quantity ARRAY<INT64>>
(['cheese', 'ham', 'salad'], [2, 5, 8], [1, 2, 1]) entry
union all
select (['othercheese', 'otherham', 'othersalad'], [3, 8, 10], [11, 22, 11])
union all
select (['othercheese', 'otherham', 'othersalad'], [3, 8, 10], [11, 22, 11])
)
SELECT ARRAY_AGG(STRUCT(item, unit_cost, quantity))
FROM data, UNNEST(entry.item) item WITH OFFSET
LEFT JOIN UNNEST(entry.unit_cost) unit_cost WITH OFFSET USING(OFFSET)
LEFT JOIN UNNEST(entry.quantity) quantity WITH OFFSET USING(OFFSET)
Output
[
{
"f0_": [
{
"item": "cheese",
"unit_cost": "2",
"quantity": "1"
},
{
"item": "ham",
"unit_cost": "5",
"quantity": "2"
},
{
"item": "salad",
"unit_cost": "8",
"quantity": "1"
},
{
"item": "othercheese",
"unit_cost": "3",
"quantity": "11"
},
{
"item": "otherham",
"unit_cost": "8",
"quantity": "22"
},
{
"item": "othersalad",
"unit_cost": "10",
"quantity": "11"
},
{
"item": "othercheese",
"unit_cost": "3",
"quantity": "11"
},
{
"item": "otherham",
"unit_cost": "8",
"quantity": "22"
},
{
"item": "othersalad",
"unit_cost": "10",
"quantity": "11"
}
]
}
]

Penalizing documents in facet results based on their content

If we have the following documents in elasticsearch:
[
{'name': 'John', 'time': '2013-01-01 12:01:00'},
{'name': 'John', 'time': '2013-01-01 12:02:00'},
{'name': 'John', 'time': '2013-01-01 12:03:00'},
{'name': 'John', 'time': '2013-01-01 12:04:00'},
{'name': 'Harry', 'time': '2013-01-01 12:05:00'},
{'name': 'Fred', 'time': '2013-01-01 12:06:00'},
{'name': 'Fred', 'time': '2013-01-01 12:07:00'}
]
And we facet over the 'name' field, we'll get something like this:
"facets": {
"count_per_name": {
"_type": "terms",
"missing": 0,
"total": 7,
"other": 0,
"terms": [
{
"term": "John",
"count": 4
},
{
"term": "Fred",
"count": 2
},
{
"term": "Harry",
"count": 1
}
]
}
}
My question is this: is it possible to perform a faceting query in elasticsearch whereby those documents with the name "John" count as "half" documents? This would lead to John's count falling from 4 to 2, but Fred's and Harry's remaining the same:
"facets": {
"count_per_name": {
"_type": "terms",
"missing": 0,
"total": 5,
"other": 0,
"terms": [
{
"term": "John",
"count": 2
},
{
"term": "Fred",
"count": 2
},
{
"term": "Harry",
"count": 1
}
]
}
}
you could play with http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-facets-terms-stats-facet.html
and specify value_script, where return 0.5 for John and 1 for other guys, and operate with SUM facet result. Though this approach is performance affected

Resources