Azure CosmosDB Query on Sub Elements - javascript

I have such documents
[
{
"id": "1",
"name": "My Product 1",
"variants": [
{
"id": 2179,
"code": "A",
"attributes": {
"att_set_1": {
"en": {
"name": "Attribute Set 1",
"data": [
{
"id": 919,
"title": "Height",
"label": "height_mm",
"v": 1200,
"unit": "mm"
},
{
"id": 921,
"title": "Weight",
"label": "weight",
"v": 500,
"unit": "kg"
},
{
"id": 923,
"title": "Other",
"label": "blah",
"v": 200,
"unit": "mm"
}
]
}
}
}
}
]
},
{
"id": "2",
"name": "My Product 2",
"variants": [
{
"id": 2180,
"code": "B",
"attributes": {
"att_set_1": {
"en": {
"name": "Attribute Set 1",
"data": [
{
"id": 919,
"title": "Height",
"label": "height_mm",
"v": 1300,
"unit": "mm"
},
{
"id": 921,
"title": "Weight",
"label": "weight",
"v": 200,
"unit": "kg"
},
{
"id": 923,
"title": "Other",
"label": "blah",
"v": 200,
"unit": "mm"
}
]
}
}
}
}
]
},
{
"id": "3",
"name": "My Product 3",
"variants": [
{
"id": 2181,
"code": "C",
"attributes": {
"att_set_1": {
"en": {
"name": "Attribute Set 1",
"data": [
{
"id": 919,
"title": "Height",
"label": "height_mm",
"v": 2000,
"unit": "mm"
},
{
"id": 921,
"title": "Weight",
"label": "weight",
"v": 999,
"unit": "kg"
},
{
"id": 923,
"title": "Other",
"label": "blah",
"v": 200,
"unit": "mm"
}
]
}
}
}
}
]
}
]
I want now to find all products where one of the variants has the Height >= 1200 and Weight >= 500
In this example this should be My Product 1 and My Product 3. My Product 2 doesn't match as the Weight Property is below the criteria.
How can I do this. Is there a way. The data structure can be changed but only if really needed.

I follow your document and created 3 sample documents as below in my cosmos db :
[
{
"id": "1",
"name": "My Product 1",
"variants": [
{
"id": 2179,
"code": "A",
"attributes": {
"att_set_1": {
"en": {
"name": "Attribute Set 1",
"data": [
{
"id": 919,
"title": "Height",
"label": "height_mm",
"v": 2330,
"unit": "mm"
},
{
"id": 921,
"title": "Weight",
"label": "weight",
"v": 2931,
"unit": "kg"
},
{
"id": 923,
"title": "Other",
"label": "blah",
"v": 200,
"unit": "mm"
}
]
}
}
}
}
]
},
{
"id": "2",
"name": "My Product 2",
"variants": [
{
"id": 2180,
"code": "B",
"attributes": {
"att_set_1": {
"en": {
"name": "Attribute Set 1",
"data": [
{
"id": 919,
"title": "Height",
"label": "height_mm",
"v": 100,
"unit": "mm"
},
{
"id": 921,
"title": "Weight",
"label": "weight",
"v": 200,
"unit": "kg"
},
{
"id": 923,
"title": "Other",
"label": "blah",
"v": 200,
"unit": "mm"
}
]
}
}
}
}
]
},
{
"id": "3",
"name": "My Product 3",
"variants": [
{
"id": 2181,
"code": "C",
"attributes": {
"att_set_1": {
"en": {
"name": "Attribute Set 1",
"data": [
{
"id": 919,
"title": "Height",
"label": "height_mm",
"v": 2000,
"unit": "mm"
},
{
"id": 921,
"title": "Weight",
"label": "weight",
"v": 999,
"unit": "kg"
},
{
"id": 923,
"title": "Other",
"label": "blah",
"v": 200,
"unit": "mm"
}
]
}
}
}
}
]
}
]
Then I use the SQL :
SELECT all FROM all join a in all.variants join b in
a.attributes.att_set_1.en.data where (b.title = 'Height' and b.v >=
2000) or (b.title = 'Weight' and b.v >= 1000)
Result data:
[
{
"all": {
"id": "1",
"name": "My Product 1",
"variants": [
{
"id": 2179,
"code": "A",
"attributes": {
"att_set_1": {
"en": {
"name": "Attribute Set 1",
"data": [
{
"id": 919,
"title": "Height",
"label": "height_mm",
"v": 2330,
"unit": "mm"
},
{
"id": 921,
"title": "Weight",
"label": "weight",
"v": 2931,
"unit": "kg"
},
{
"id": 923,
"title": "Other",
"label": "blah",
"v": 200,
"unit": "mm"
}
]
}
}
}
}
]
}
},
{
"all": {
"id": "1",
"name": "My Product 1",
"variants": [
{
"id": 2179,
"code": "A",
"attributes": {
"att_set_1": {
"en": {
"name": "Attribute Set 1",
"data": [
{
"id": 919,
"title": "Height",
"label": "height_mm",
"v": 2330,
"unit": "mm"
},
{
"id": 921,
"title": "Weight",
"label": "weight",
"v": 2931,
"unit": "kg"
},
{
"id": 923,
"title": "Other",
"label": "blah",
"v": 200,
"unit": "mm"
}
]
}
}
}
}
]
},
{
"all": {
"id": "3",
"name": "My Product 3",
"variants": [
{
"id": 2181,
"code": "C",
"attributes": {
"att_set_1": {
"en": {
"name": "Attribute Set 1",
"data": [
{
"id": 919,
"title": "Height",
"label": "height_mm",
"v": 2000,
"unit": "mm"
},
{
"id": 921,
"title": "Weight",
"label": "weight",
"v": 999,
"unit": "kg"
},
{
"id": 923,
"title": "Other",
"label": "blah",
"v": 200,
"unit": "mm"
}
]
}
}
}
}
]
}
}
]
Please notice that the value column is a keyword and cannot be used in a document. So, in my documents I remove it with v.
Update Answer:
After a few attempts, it seems impossible to directly query the results you want from the the Cosmos DB via the SQL statement.
However , Cosmos DB provides us with Stored Procedure when we face complex queries. If you do not know much about stored procedure, you can read this article.
Please refer to the stored procedure I created as below :
function sample() {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT * FROM c',
function (err, feed, options) {
if (err) throw err;
var returnArray = [];
if (!feed || !feed.length){
getContext().getResponse().setBody('no docs found');
} else{
for(var i=0;i<feed.length;i++){
var foundHeight = false, foundWeight=false;
var dataArray = feed[i].variants[0].attributes.att_set_1.en.data;
for(var j=0;j<dataArray.length;j++){
var f = dataArray[j];
if((f.title=='Height'&&f.v>=2000){
foundHeight = true;
} else if(f.title=='Weight'&&f.v>=1000)){
foundWeight = true;
}
}
if(foundHeight && foundWeight)
returnArray.push(feed[i]);
}
}
getContext().getResponse().setBody(JSON.stringify(returnArray));
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
Output result :
[
{
"id": "1",
"name": "My Product 1",
"variants": [
{
"id": 2179,
"code": "A",
"attributes": {
"att_set_1": {
"en": {
"name": "Attribute Set 1",
"data": [
{
"id": 919,
"title": "Height",
"label": "height_mm",
"v": 2330,
"unit": "mm"
},
{
"id": 921,
"title": "Weight",
"label": "weight",
"v": 2931,
"unit": "kg"
},
{
"id": 923,
"title": "Other",
"label": "blah",
"v": 200,
"unit": "mm"
}
]
}
}
}
}
]
},
{
"id": "3",
"name": "My Product 3",
"variants": [
{
"id": 2181,
"code": "C",
"attributes": {
"att_set_1": {
"en": {
"name": "Attribute Set 1",
"data": [
{
"id": 919,
"title": "Height",
"label": "height_mm",
"v": 2000,
"unit": "mm"
},
{
"id": 921,
"title": "Weight",
"label": "weight",
"v": 999,
"unit": "kg"
},
{
"id": 923,
"title": "Other",
"label": "blah",
"v": 200,
"unit": "mm"
}
]
}
}
}
}
]
}
]
This result should be what you want. You can create it on portal or in your code. Any concern ,please let me know.
Hope it helps you.

Related

How do I solve this task in javascript? [duplicate]

This question already has answers here:
How to groupBy array of objects based on properties in vanilla javascript
(2 answers)
Closed 2 years ago.
I got a json file that contains beer types like this:
{
"type": "Unifiltered",
"name": "Heineken Unfiltered",
"id": "XY",
"brand": "Heineken",
"price": "1250",
"alcohol": "0.04",
"ingredients": [
{
"id": "XY2",
"ratio": "0.15",
"name": "salt"
},
{
"id": "XY3",
"ratio": "0.00",
"name": "sugar"
},
{
"id": "XY4",
"ratio": "0.35",
"name": "barley"
}
],
"isCan": false
},
My task is to group beers by brand:
My friend has a list of all the beers available in his pub, but it’s a huge mess.
He would like to see the beers grouped by brands.
My friend also told you that the Function should return an array of Brand > objects which contain the array of Beers of that Brand.
Example:
[{brand: Heineken, beers: [{...}, ...]}]"
const beers = [{
"type": "Unifiltered",
"name": "Heineken Unfiltered",
"id": "XY",
"brand": "Heineken",
"price": "1250",
"alcohol": "0.04",
"ingredients": [
{
"id": "XY2",
"ratio": "0.15",
"name": "salt"
},
{
"id": "XY3",
"ratio": "0.00",
"name": "sugar"
},
{
"id": "XY4",
"ratio": "0.35",
"name": "barley"
}
],
"isCan": false
},
{
"type": "type",
"name": "name",
"id": "XY",
"brand": "EFES",
"price": "1250",
"alcohol": "0.04",
"ingredients": [
{
"id": "XY2",
"ratio": "0.15",
"name": "salt"
},
{
"id": "XY3",
"ratio": "0.00",
"name": "sugar"
},
{
"id": "XY4",
"ratio": "0.35",
"name": "barley"
}
],
"isCan": false
},
{
"type": "type3",
"name": "name2",
"id": "XY",
"brand": "EFES",
"price": "1250",
"alcohol": "0.04",
"ingredients": [
{
"id": "XY2",
"ratio": "0.15",
"name": "salt"
},
{
"id": "XY3",
"ratio": "0.00",
"name": "sugar"
},
{
"id": "XY4",
"ratio": "0.35",
"name": "barley"
}
],
"isCan": false
}];
var group = beers.reduce((r, a) => {
r[a. brand] = [...r[a. brand] || [], a];
return r;
}, {});
console.log("group", group);
i think its already answered here
let group = beers.reduce((r, a) => {
r[a. brand] = [...r[a. brand] || [], a];
return r;
}, {});
console.log("group", group);
Written in an easily readable format, using array.forEach() in place of shorthand functions:
let beers = [{
"type": "Unifiltered",
"name": "Heineken Unfiltered",
"id": "XY",
"brand": "Heineken",
"price": "1250",
"alcohol": "0.04",
"ingredients": [
{
"id": "XY2",
"ratio": "0.15",
"name": "salt"
},
{
"id": "XY3",
"ratio": "0.00",
"name": "sugar"
},
{
"id": "XY4",
"ratio": "0.35",
"name": "barley"
}
],
"isCan": false
}];
let brands = [];
// Loop over all beers
beers.forEach((beer) => {
// Try to find beer brand in existing list of brand
let brand = brands.filter((brand) => brand.brand === beer.brand)[0];
if(brand) {
// If we find it, push the beer onto the beer property
brand.beers.push(beer);
} else {
// If we don't find it, create a new brand and push it onto brands
brand = {
brand: beer.brand,
beers: [beer]
}
brands.push(brand);
}
});
console.log(brands);
I think Grouping JSON by values can be useful. Using the group_by function and then its is just cleaning up the answer to get what you need.

How to get a specific object from whole object?

I am trying to get specific object from a whole object below is the example
by using localStorage.getItem('shop/elasticCache/shirt');
I get below data
{"description":"Tech Shirt","configurable_options":[{"attribute_id":80,"values":[{"value_index":"5176","label":"RUST"}],"label":"Color","attribute_code":"color"},{"attribute_id":125,"values":[{"value_index":"2898","label":"Small"},{"value_index":"2901","label":"Medium"},{"value_index":"2904","label":"Large"}],"label":"Size","attribute_code":"size"}],"tsk":1594790209,"size_options":[2898,2901,2904],"regular_price":28,"final_price":null,"price":28,"color_options":[5176],"special_from_date":null,"id":250659,"category":[{"category_id":2,"name":"Default Category","position":1},{"category_id":3,"name":"Clothing","position":14985},{"category_id":30,"name":"Bottoms","position":798},{"category_id":58,"name":"Leggings","position":1},{"category_id":1130,"name":"Char Test Category","position":30}],"sku":"S155551","product_links":[{"link_type":"related","linked_product_sku":null,"linked_product_type":null,"position":0,"sku":"P100031"},{"link_type":"related","linked_product_sku":null,"linked_product_type":null,"position":0,"sku":"P100031"}
I am trying to get
{"category_id":3,"name":"Clothing","position":14985},{"category_id":30,"name":"Bottoms","position":798},{"category_id":58,"name":"Leggings","position":1},{"category_id":1130,"name":"Char Test Category","position":30}]
Is their any way it can be done ?
const {category} = JSON.parse(localStorage.getItem('shop/elasticCache/shirt');)
or
const {category } = {
"description": "Tech Shirt",
"configurable_options": [{
"attribute_id": 80,
"values": [{
"value_index": "5176",
"label": "RUST"
}],
"label": "Color",
"attribute_code": "color"
}, {
"attribute_id": 125,
"values": [{
"value_index": "2898",
"label": "Small"
}, {
"value_index": "2901",
"label": "Medium"
}, {
"value_index": "2904",
"label": "Large"
}],
"label": "Size",
"attribute_code": "size"
}],
"tsk": 1594790209,
"size_options": [2898, 2901, 2904],
"regular_price": 28,
"final_price": null,
"price": 28,
"color_options": [5176],
"special_from_date": null,
"id": 250659,
"category": [{
"category_id": 2,
"name": "Default Category",
"position": 1
}, {
"category_id": 3,
"name": "Clothing",
"position": 14985
}, {
"category_id": 30,
"name": "Bottoms",
"position": 798
}, {
"category_id": 58,
"name": "Leggings",
"position": 1
}, {
"category_id": 1130,
"name": "Char Test Category",
"position": 30
}],
"sku": "S155551",
"product_links": [{
"link_type": "related",
"linked_product_sku": null,
"linked_product_type": null,
"position": 0,
"sku": "P100031"
}, {
"link_type": "related",
"linked_product_sku": null,
"linked_product_type": null,
"position": 0,
"sku": "P100031"
}]
}
objc={"description":"Tech Shirt","configurable_options":
[{"attribute_id":80,"values":[{"value_index":"5176","label":"RUST"}],
"label":"Color","attribute_code":"color"},
{"attribute_id":125,"values":[{"value_index":"2898","label":"Small"}
,{"value_index":"2901","label":"Medium"},
{"value_index":"2904","label":"Large"}],
"label":"Size","attribute_code":"size"}],
"tsk":1594790209,"size_options":[2898,2901,2904]
,"regular_price":28,"final_price":null,"price":28,
"color_options":[5176],"special_from_date":null,"id":250659,
"category":[{"category_id":2,"name":"Default Category","position":1},
{"category_id":3,"name":"Clothing","position":14985},
{"category_id":30,"name":"Bottoms","position":798},
{"category_id":58,"name":"Leggings","position":1},
{"category_id":1130,"name":"Char Test Category","position":30}],
"sku":"S155551","product_links":
[{"link_type":"related","linked_product_sku":null,"linked_product_type":null,"position":0,"sku":"P100031"},
{"link_type":"related","linked_product_sku":null,"linked_product_type":null,"position":0,"sku":"P100031"}]
}
res = objc["category"]
res.shift()
console.log(res)
$(document).ready(function () {
var jsonObj = {
"description": "Tech Shirt",
"configurable_options": [{
"attribute_id": 80,
"values": [{
"value_index": "5176",
"label": "RUST"
}],
"label": "Color",
"attribute_code": "color"
}, {
"attribute_id": 125,
"values": [{
"value_index": "2898",
"label": "Small"
}, {
"value_index": "2901",
"label": "Medium"
}, {
"value_index": "2904",
"label": "Large"
}],
"label": "Size",
"attribute_code": "size"
}],
"tsk": 1594790209,
"size_options": [2898, 2901, 2904],
"regular_price": 28,
"final_price": null,
"price": 28,
"color_options": [5176],
"special_from_date": null,
"id": 250659,
"category": [{
"category_id": 2,
"name": "Default Category",
"position": 1
}, {
"category_id": 3,
"name": "Clothing",
"position": 14985
}, {
"category_id": 30,
"name": "Bottoms",
"position": 798
}, {
"category_id": 58,
"name": "Leggings",
"position": 1
}, {
"category_id": 1130,
"name": "Char Test Category",
"position": 30
}],
"sku": "S155551",
"product_links": [{
"link_type": "related",
"linked_product_sku": null,
"linked_product_type": null,
"position": 0,
"sku": "P100031"
}, {
"link_type": "related",
"linked_product_sku": null,
"linked_product_type": null,
"position": 0,
"sku": "P100031"
}]
};
for(var i = 1; i < jsonObj.category.length; i++){
console.log(jsonObj.category[i]);
}
});
You can iterate through the entire object and can get the required values. The above code gives the values of category from index 1.

More efficient way to remove from an object attributes present in a group of objects

I'm manipulating some javascript objects and I want to know if is there a more efficient and easy way to process my data.
I already do that, but I'm a beginner in js.
I have four objects with this structure: basically there is an array of blocks and any object has a different number of blocks. In every block, in the features attribute, I have another array with some features.
Then I have another object, and I have to remove from this object (I call it structure) blocks and features that are not present in my four initial object.
This is a sample product object
[
{
"ID": 16293,
"SortNo": "20",
"FeatureGroup": {
"ID": "148",
"Name": {
"Value": "Design",
"Language": "IT"
}
},
"Features": [
{
"Localized": 0,
"ID": "155744521",
"Type": "dropdown",
"Value": "Round",
"CategoryFeatureId": "85327",
"CategoryFeatureGroupID": "16293",
"SortNo": "155",
"PresentationValue": "Rotondo",
"RawValue": "Round",
"LocalValue": [],
"Description": "The external form",
"Mandatory": "1",
"Searchable": "0",
"Feature": {
"ID": "9397",
"Sign": "",
"Measure": {
"ID": "29",
"Sign": "",
"Signs": {
"ID": "",
"_": "",
"Language": "IT"
}
},
"Name": {
"Value": "Forma",
"Language": "IT"
}
}
},
{
"Localized": 0,
"ID": "155655523",
"Type": "multi_dropdown",
"Value": "White",
"CategoryFeatureId": "85298",
"CategoryFeatureGroupID": "16293",
"SortNo": "90",
"PresentationValue": "Bianco",
"RawValue": "White",
"LocalValue": [],
"Description": "The colour of the housing",
"Mandatory": "1",
"Searchable": "1",
"Feature": {
"ID": "10059",
"Sign": "",
"Measure": {
"ID": "29",
"Sign": "",
"Signs": {
"ID": "",
"_": "",
"Language": "IT"
}
},
"Name": {
"Value": "Colore struttura",
"Language": "IT"
}
}
},
{
"Localized": 0,
"ID": "155655525",
"Type": "multi_dropdown",
"Value": "White",
"CategoryFeatureId": "85301",
"CategoryFeatureGroupID": "16293",
"SortNo": "80",
"PresentationValue": "Bianco",
"RawValue": "White",
"LocalValue": [],
"Description": "The colour of the band",
"Mandatory": "1",
"Searchable": "1",
"Feature": {
"ID": "11025",
"Sign": "",
"Measure": {
"ID": "29",
"Sign": "",
"Signs": {
"ID": "",
"_": "",
"Language": "IT"
}
},
"Name": {
"Value": "Colore cinturino",
"Language": "IT"
}
}
},
{
"Localized": 0,
"ID": "219617494",
"Type": "y_n",
"Value": "Y",
"CategoryFeatureId": "168947",
"CategoryFeatureGroupID": "16293",
"SortNo": "-6",
"PresentationValue": "Sì",
"RawValue": "Y",
"LocalValue": [],
"Description": "The product is protected from water",
"Mandatory": "0",
"Searchable": "0",
"Feature": {
"ID": "7509",
"Sign": "",
"Measure": {
"ID": "26",
"Sign": "",
"Signs": {
"ID": "",
"_": "",
"Language": "IT"
}
},
"Name": {
"Value": "Resistente all'acqua",
"Language": "IT"
}
}
}
]
},
{
"ID": 34567,
"SortNo": "20",
"FeatureGroup": {
"ID": "184",
"Name": {
"Value": "Prestazione",
"Language": "IT"
}
},
"Features": [
{
"Localized": 0,
"ID": "155744528",
"Type": "y_n",
"Value": "N",
"CategoryFeatureId": "94697",
"CategoryFeatureGroupID": "34567",
"SortNo": "800",
"PresentationValue": "No",
"RawValue": "N",
"LocalValue": [],
"Description": "La Frequenza modulare radio produce la miglior recezione di qualsiasi canale radio. Quando viene usato un auricolare, produce un effetto di suono da stereo r",
"Mandatory": "1",
"Searchable": "0",
"Feature": {
"ID": "2172",
"Sign": "",
"Measure": {
"ID": "26",
"Sign": "",
"Signs": {
"ID": "",
"_": "",
"Language": "IT"
}
},
"Name": {
"Value": "Radio FM",
"Language": "IT"
}
}
},
{
"Localized": 0,
"ID": "155744530",
"Type": "multi_dropdown",
"Value": "Not supported",
"CategoryFeatureId": "85357",
"CategoryFeatureGroupID": "34567",
"SortNo": "500",
"PresentationValue": "Non supportato",
"RawValue": "Not supported",
"LocalValue": [],
"Description": "Types of memory cards which can be used with this product.",
"Mandatory": "1",
"Searchable": "0",
"Feature": {
"ID": "730",
"Sign": "",
"Measure": {
"ID": "29",
"Sign": "",
"Signs": {
"ID": "",
"_": "",
"Language": "IT"
}
},
"Name": {
"Value": "Tipi schede di memoria",
"Language": "IT"
}
}
}
]
}
]
Here i loop my initial objects (this.compare_products) to extract, in two arrays (featureGroupIds - featureIds) the ID of my block and the CategoryFeatureId
let featureGroupIds = []
let featureIds = []
this.compare_products.forEach((object) => {
featureGroupIds = featureGroupIds.concat(FeaturesGroups.map(o => o.ID))
featureIds = featureIds.concat(FeaturesGroups.map(o => o.Features.map(o => o. CategoryFeatureId))).flat(2)
})
The two arrays, featureGroupIds and featureIds are now filled with every block ID and every CategoryFeatureId present in my four object.
Now I have to filter the object I call "structure" to remove the block and the features with an ID that is not present in my arrays.
This is my structure, and as you can see is similar.
[
{
"name": "Display",
"data": {
"id": 34566,
"category_id": 2647
},
"features": [
{
"name": "Tipo di display",
"data": {
"id": 85325,
"category_id": 2647,
"feature_id": 9104,
"category_feature_group_id": 34566,
"order": 10100140
}
},
{
"name": "Touch screen",
"data": {
"id": 85331,
"category_id": 2647,
"feature_id": 4963,
"category_feature_group_id": 34566,
"order": 10100129
}
},
{
"name": "Dimensioni schermo",
"data": {
"id": 158002,
"category_id": 2647,
"feature_id": 3544,
"category_feature_group_id": 34566,
"order": 100149
}
},
{
"name": "à di Pixel",
"data": {
"id": 85347,
"category_id": 2647,
"feature_id": 13246,
"category_feature_group_id": 34566,
"order": 100147
}
},
{
"name": "Tipo di vetro",
"data": {
"id": 94704,
"category_id": 2647,
"feature_id": 7610,
"category_feature_group_id": 34566,
"order": 100050
}
}
]
},
{
"name": "Altre caratteristiche",
"data": {
"id": 34569,
"category_id": 2647,
"feature_group_id": 146,
"name": null,
"order": 0
},
"features": [
{
"name": "inside",
"data": {
"id": 110410,
"category_id": 2647,
"feature_id": 18688,
"category_feature_group_id": 34569,
"order": 100000
}
}
]
}
]
Here is my function
structure = structure.filter(featureGroup => this.featureGroupIds.includes(featureGroup.data.id));
structure.map((object) => {
object.features.filter(feature => this.featureIds.includes(feature.data.feature_id))
})
this.featureIds and this.featureGroupIds are the array with the group IDS and with the feature IDS.
Is there a more efficient way to do this?

Javascript Recursive function to build Tree

Hi I am using JavaScript and jQuery as client side script. I am little bit new to Recursive functions. I have a JSON data as below and I have tried to make a tree structure using below JSON data by writing a recursive function but I am not able to build the tree structure.
var jsonData = { "$id": "45", "_children": [{ "$id": "46", "_children": [{ "$id": "47", "_children": [{ "$id": "48", "_children": [{ "$id": "49", "_children": null, "id": "Test1", "text": "Text1", "name": "name1", "parent": null, "root": { "$ref": "49" }, "depth": 0, "children": [] }], "id": "id1", "text": "text2", "name": "name2", "parent": null, "root": { "$ref": "48" }, "depth": 0, "children": [{ "$ref": "49" }] }], "id": "id3", "text": "text4", "name": "name4", "parent": null, "root": { "$ref": "47" }, "depth": 0, "children": [{ "$ref": "48" }] }, { "$id": "50", "_children": [{ "$id": "51", "_children": [{ "$id": "52", "_children": null, "id": "id6", "text": "text6", "name": "name6", "parent": null, "root": { "$ref": "52" }, "depth": 0, "children": [] }], "id": "id7", "text": "text7", "name": "name7", "parent": null, "root": { "$ref": "51" }, "depth": 0, "children": [{ "$ref": "52" }] }], "id": "id8", "text": "text8", "name": "name8", "parent": null, "root": { "$ref": "50" }, "depth": 0, "children": [{ "$ref": "51" }] }], "id": "id9", "text": "text9", "name": "name9", "parent": null, "root": { "$ref": "46" }, "depth": 0, "children": [{ "$ref": "47" }, { "$ref": "50" }] }, { "$id": "53", "_children": [{ "$id": "54", "_children": null, "id": "id10", "text": "text10", "name": "name10", "parent": null, "root": { "$ref": "54" }, "depth": 0, "children": [] }], "id": "id11", "text": "text11", "name": "name11", "parent": null, "root": { "$ref": "53" }, "depth": 0, "children": [{ "$ref": "54" }] }], "id": "0", "text": "0", "name": "", "parent": null, "root": { "$ref": "45" }, "depth": 0, "children": [{ "$ref": "46" }, { "$ref": "53" }] }
Required Output:
var treeNode = {
id: 101, // random
text: object.name,
icon: "fas fa-plus",
subNode: {
// id, text, icon and subNode of Children object
// recursive data, So on....
}
};
Can anyone suggest me or help me to write javascript or jQuery Recursive function based on above JSON data so I can build tree structure. I know I am asking about help because I do have less knowledge about recursive function.
If we abstract this a bit, it's pretty easy to write a general-purpose tree-mapping function. Then we can supply two callback functions: one to find the child nodes of the input and one to build the output node based on the input and the mapped children. Such a function turns out to be surprisingly simple:
const mapTree = (getChildren, transformNode) => (tree) =>
transformNode (
tree,
(getChildren (tree) || []) .map (mapTree (getChildren, transformNode))
)
For your data, getChildren is simply (node) => node._children
And the node transformation might be as simple as:
const transformNode = (node, children) =>
({
id: node.$id, // or a randomizing call?
text: node.name,
icon: "fas fa-plus", // is this really a fixed value?
subNode: children
})
Putting this together we get
const mapTree = (getChildren, transformNode) => (tree) =>
transformNode (
tree,
(getChildren (tree) || []) .map (mapTree (getChildren, transformNode))
)
const kids = (node) => node._children
const transformNode = (node, children) =>
({
id: node.$id,
text: node.name,
icon: "fas fa-plus",
subNode: children
})
const myTransform = mapTree (kids, transformNode)
const jsonData = { "$id": "45", "_children": [{ "$id": "46", "_children": [{ "$id": "47", "_children": [{ "$id": "48", "_children": [{ "$id": "49", "_children": null, "id": "Test1", "text": "Text1", "name": "name1", "parent": null, "root": { "$ref": "49" }, "depth": 0, "children": [] }], "id": "id1", "text": "text2", "name": "name2", "parent": null, "root": { "$ref": "48" }, "depth": 0, "children": [{ "$ref": "49" }] }], "id": "id3", "text": "text4", "name": "name4", "parent": null, "root": { "$ref": "47" }, "depth": 0, "children": [{ "$ref": "48" }] }, { "$id": "50", "_children": [{ "$id": "51", "_children": [{ "$id": "52", "_children": null, "id": "id6", "text": "text6", "name": "name6", "parent": null, "root": { "$ref": "52" }, "depth": 0, "children": [] }], "id": "id7", "text": "text7", "name": "name7", "parent": null, "root": { "$ref": "51" }, "depth": 0, "children": [{ "$ref": "52" }] }], "id": "id8", "text": "text8", "name": "name8", "parent": null, "root": { "$ref": "50" }, "depth": 0, "children": [{ "$ref": "51" }] }], "id": "id9", "text": "text9", "name": "name9", "parent": null, "root": { "$ref": "46" }, "depth": 0, "children": [{ "$ref": "47" }, { "$ref": "50" }] }, { "$id": "53", "_children": [{ "$id": "54", "_children": null, "id": "id10", "text": "text10", "name": "name10", "parent": null, "root": { "$ref": "54" }, "depth": 0, "children": [] }], "id": "id11", "text": "text11", "name": "name11", "parent": null, "root": { "$ref": "53" }, "depth": 0, "children": [{ "$ref": "54" }] }], "id": "0", "text": "0", "name": "", "parent": null, "root": { "$ref": "45" }, "depth": 0, "children": [{ "$ref": "46" }, { "$ref": "53" }] }
console .log (myTransform (jsonData))
This does something slightly different from your requested output. You had written subNode: { ... }, but instead I'm returning an array of objects, subNodes: [ ... ], as I don't make any real sense of a plain object here.
Also, this will yield an empty subNodes array if an input node has no children. If you would rather not have the subNodes property, you could replace
subNode: children
with something like
...(children .length ? {subNode: children} : {})
Obviously, you don't need the named helpers and could call mapTree with anonymous functions like this:
const myTransform = mapTree (
(node) => node._children,
(node, children) =>
({
id: node.$id,
text: node.name,
icon: "fas fa-plus",
subNode: children
})
)
This mapTree function was very easy to write, as I didn't have to think about any details of the output or input formats as I wrote it. But perhaps that abstraction is not helpful to me, and I'm never going to use it except here. If so, I can simply rework the abstract version by plugging the hard-coded callbacks directly. With only a little manipulation, that will turn it into this version:
const newTransform = (node) =>
({
id: node.$id,
text: node.name,
icon: "fas fa-plus",
subNode: (node._children || []).map(newTransform)
})
const jsonData = { "$id": "45", "_children": [{ "$id": "46", "_children": [{ "$id": "47", "_children": [{ "$id": "48", "_children": [{ "$id": "49", "_children": null, "id": "Test1", "text": "Text1", "name": "name1", "parent": null, "root": { "$ref": "49" }, "depth": 0, "children": [] }], "id": "id1", "text": "text2", "name": "name2", "parent": null, "root": { "$ref": "48" }, "depth": 0, "children": [{ "$ref": "49" }] }], "id": "id3", "text": "text4", "name": "name4", "parent": null, "root": { "$ref": "47" }, "depth": 0, "children": [{ "$ref": "48" }] }, { "$id": "50", "_children": [{ "$id": "51", "_children": [{ "$id": "52", "_children": null, "id": "id6", "text": "text6", "name": "name6", "parent": null, "root": { "$ref": "52" }, "depth": 0, "children": [] }], "id": "id7", "text": "text7", "name": "name7", "parent": null, "root": { "$ref": "51" }, "depth": 0, "children": [{ "$ref": "52" }] }], "id": "id8", "text": "text8", "name": "name8", "parent": null, "root": { "$ref": "50" }, "depth": 0, "children": [{ "$ref": "51" }] }], "id": "id9", "text": "text9", "name": "name9", "parent": null, "root": { "$ref": "46" }, "depth": 0, "children": [{ "$ref": "47" }, { "$ref": "50" }] }, { "$id": "53", "_children": [{ "$id": "54", "_children": null, "id": "id10", "text": "text10", "name": "name10", "parent": null, "root": { "$ref": "54" }, "depth": 0, "children": [] }], "id": "id11", "text": "text11", "name": "name11", "parent": null, "root": { "$ref": "53" }, "depth": 0, "children": [{ "$ref": "54" }] }], "id": "0", "text": "0", "name": "", "parent": null, "root": { "$ref": "45" }, "depth": 0, "children": [{ "$ref": "46" }, { "$ref": "53" }] }
console .log (newTransform (jsonData))
There's an important point here. This generic function was much easier to write than if I'd tried to write something to convert your format directly. While there is a danger in too-early abstraction, it also can offer significant benefits. I might well choose to keep only that last version, but the generic abstraction simplified the development of it.
It can be something like that, with using the json data model
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="lib/style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<div id="myDiv"></div>
</body>
<script>
var treeData={
"Id":"10",
"text":"Document Categories",
"icon":"fas fa-plus",
"subNode":
[
{
"Id":"11",
"text":"Pdf Documents",
"icon":"fas fa-plus",
"subNode":[
{
"Id":"31",
"text":"Book Pdfs",
"icon":"fas fa-plus",
"subNode":[]
},
{
"Id":"32",
"text":"EPub",
"icon":"fas fa-plus",
"subNode":[
{
"Id":"20",
"text":"EBook Epubs1",
"icon":"fas fa-plus",
"subNode":[]
},
{
"Id":"30",
"text":"EBook Epubs2",
"icon":"fas fa-plus",
"subNode":[]
}
]
}
]
},
{
"Id":"33",
"text":"Text Documents",
"icon":"fas fa-plus",
"subNode":[
{
"Id":"32",
"text":"Book Text",
"icon":"fas fa-plus",
"subNode":[]
},
{
"Id":"35",
"text":"Automatic Text",
"icon":"fas fa-plus",
"subNode":[]
}
]
}
]
};
var newTree = AddRecursive(null, treeData);
var treeDiv = $('#myDiv');
treeDiv.append(newTree);
function AddRecursive(tree, data) {
if (tree == null) {
tree = $('<ul/>');
tree.attr('id', 'treeID');
}
var listU = $('<ul />');
listU.addClass('ul class');
var listItem = $('<li />');
listItem.addClass('li class');
listItem.attr('data-id', data.Id);
var link = $('<a />');
var i = $('<i/>').addClass('fa fa-folder');
link.append(i);
//link.addClass("linkClass");
link.append(data.text);
listItem.append(link);
if (data.subNode.length > 0) {
var span = $(' <span />');
span.addClass('fa-chevron-down');
link.append(span);
}
listU.append(listItem);
tree.append(listU);
for (i in data.subNode) {
AddRecursive(listItem, data.subNode[i]);
}
return tree;
}
</script>
</html>

how to declare a double array in javascript for this particular UI

Hi i am making an UI that is given in this link plunker link
i have a resourceType in json file which have different number of array inside it.I have to get it from the json and pass it to the function span1 so i could add it to span where it will pop up as table.Right now i am getting only one value using one D-array.can you please help me
"details": [{
"id": "1",
"name": "AOB",
"width": "10",
"color1": "#FF3300",
"ResourceType": [{
"types": "Ground services",
"category": "employee",
"count": "1",
"skills": "wing walker"
}]
}, {
"id": "1",
"name": "CC",
"width": "20",
"color1": "#FF3300",
"ResourceType": [{
"types": "cleaner",
"category": "employee",
"count": "20",
"skills": "cabin cleaning"
}, {
"types": "cleaner",
"category": "employee",
"count": "2",
"skills": "trash collector"
}, {
"types": "supervisor",
"category": "employee",
"count": "1",
"skills": "cabin cleaning"
}]
}, {
"id": "2",
"name": "MB",
"width": "50",
"color1": "#00FFFF",
"ResourceType": [{
"types": "engineer",
"category": "employee",
"count": "1",
"skills": "B1"
}, {
"types": "mechanic",
"category": "employee",
"count": "2",
"skills": "B1"
}]
}, {
"id": "2",
"name": "TS",
"width": "100",
"color1": "#00FFFF",
"ResourceType": [{
"types": "groundservices",
"category": "employee",
"count": "1",
"skills": "drivers"
}, {
"types": "Toilet Truck",
"category": "vehicle",
"count": "1"
}]
}, {
"id": "2",
"name": "WS",
"width": "80",
"color1": "#00FFFF",
"ResourceType": [{
"types": "ground services",
"category": "employee",
"count": "1",
"skills": "drivers"
}, {
"types": "Water Truck",
"category": "vehicle",
"count": "1"
}]
}, {
"id": "2",
"name": "R",
"width": "60",
"color1": "#00FFFF",
"ResourceType": [{
"types": "ground services",
"category": "employee",
"count": "1",
"skills": "refuelling"
}]
}, {
"id": "3",
"name": "AOB",
"width": "50",
"color1": "#66FF66",
"ResourceType": [{
"types": "ground services",
"category": "employee",
"count": "1",
"skills": "wing walker"
}]
}, {
"id": "3",
"name": "PB",
"width": "20",
"color1": "#66FF66",
"ResourceType": [{
"types": "ground services",
"category": "employee",
"count": "1",
"skills": "driver"
}, {
"types": "tow tractor",
"category": "vehicle",
"count": "1"
}, {
"types": "ground services",
"category": "equipment",
"count": "1"
}]
}]
the resource type is shown in this json
function span1(left1,width,id,color11,name,types,category,count,skills){
id = "c" +id ;
var k=width;
var s="<span class='" + id + "'style='border: 1px Solid Black;position:absolute;height:25px;left:" + left1 + "px;background-color:" + color11 + ";width:" + k + "px'>" + name + "<div class='tooltip'><table id='jumble'><tbody><tr><th>Resource Type</th><th>Resource Category</th><th>Resources</th><th>Skills</th></tr> <tr><td>"+ types + "</td><td>" + category + "</td><td>" + count +"</td><td>" +skills +"</td></tr></tbody></table></div></span>";
s = s + "<div style='border-color:white;height:5px;'></div>";
return s;
}
my span1 function
You can access ResourceType in following way -
for(var i = 0; i < details.length; i++)
{
var resourceArray = details[i].ResourceType;
// since ResourceType is an array as well you can have following -
if(resourceArray && resourceArray.length > 0)
{
for(var j = 0; j < resourceArray.length; j++)
{
// following contains the data you want
var resourceData = resourceArray[j];
// since resourceData is an object you can access with . notation
// call your span1 function here
span1(left1,details[i].width, details[i].id,details[i].color11,details[i].name,resourceData.types,resourceData.category,resourceData.count,resourceData.skills);
}
}
}

Categories