I have an object similar to this one:
const obj = { operator: 'AND', attributes: [ { attribute: 'attr1', value: '123' }, { attribute: 'attr2', value: '234' }, { operator: 'OR', attributes: [ { attribute: 'attr3', value: 'xxx' } ] } ] }
And I want to construct a tree from it:
{ "id": "9aabbb89-cdef-4012-b456-7178a79bf800", "type": "group", "path": [ "9aabbb89-cdef-4012-b456-7178a79bf800" ], "children1": { "a89aaa88-0123-4456-b89a-b178a79c0aab": { "type": "rule", "id": "a89aaa88-0123-4456-b89a-b178a79c0aab", "properties": { "attribute": "attr1", "value": "123" }, "path": [ "9aabbb89-cdef-4012-b456-7178a79bf800", "a89aaa88-0123-4456-b89a-b178a79c0aab" ] }, "a9babbb8-cdef-4012-b456-7178a79c35ab": { "type": "rule", "id": "a9babbb8-cdef-4012-b456-7178a79c35ab", "properties": { "attribute": "attr2", "value": "234" }, "path": [ "9aabbb89-cdef-4012-b456-7178a79bf800", "a9babbb8-cdef-4012-b456-7178a79c35ab" ] }, "b9aaabb9-0123-4456-b89a-b178a79cc5c2": { "type": "group", "id": "b9aaabb9-0123-4456-b89a-b178a79cc5c2", "properties": { "conjunction": "OR" }, "path": [ "9aabbb89-cdef-4012-b456-7178a79bf800", "b9aaabb9-0123-4456-b89a-b178a79cc5c2" ], "children1": { "9baa88b9-cdef-4012-b456-7178a79cc5c3": { "type": "rule", "id": "9baa88b9-cdef-4012-b456-7178a79cc5c3", "properties": { "attribute": "attr3", "value": "xxx" }, "path": [ "9aabbb89-cdef-4012-b456-7178a79bf800", "b9aaabb9-0123-4456-b89a-b178a79cc5c2", "9baa88b9-cdef-4012-b456-7178a79cc5c3" ] } } } } }
I write this code to create the tree:
function buildTree(obj) { if (!obj || !Object.keys(obj).length) return {}; if ( 'attribute' in obj) { const id = uuid4(); return {[id]: { id, type: 'rule', properties: { attribute: obj.attribute, value: obj.value, }, } } } if (obj.operator === 'AND' || obj.operator === 'OR') { return { id: uuid4(), type: 'group', properties: { conjunction: obj.operator }, children1: obj.operands.map(buildTree), } } }
However, I’m stucked how to keep the track of the parent ids of a children and save them in a path
attribute. How can I fix that?
Advertisement
Answer
You have a recursive function, so just pass the path
down through the calls (starting with an empty array) and append to it as you go:
function buildTree(obj, path = []) { if (!obj || !Object.keys(obj).length) return {}; const id = uuid4() const newPath = [...path, id]; if ('attribute' in obj) { return { [id]: { id, type: 'rule', path: newPath, properties: { attribute: obj.attribute, value: obj.value, }, } } } if (obj.operator === 'AND' || obj.operator === 'OR') { return { id: id, type: 'group', path: newPath, properties: { conjunction: obj.operator }, children1: obj.attributes.map(x => buildTree(x, newPath)), } } } const obj = { operator: 'AND', attributes: [{ attribute: 'attr1', value: '123' }, { attribute: 'attr2', value: '234' }, { operator: 'OR', attributes: [{ attribute: 'attr3', value: 'xxx' }] } ] } function uuid4() { let array = new Uint8Array(16) crypto.getRandomValues(array) // Manipulate the 9th byte array[8] &= 0b00111111 // Clear the first two bits array[8] |= 0b10000000 // Set the first two bits to 10 // Manipulate the 7th byte array[6] &= 0b00001111 // Clear the first four bits array[6] |= 0b01000000 // Set the first four bits to 0100 const pattern = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" let idx = 0 return pattern.replace( /XX/g, () => array[idx++].toString(16).padStart(2, "0"), // padStart ensures a leading zero, if needed ) } console.log(buildTree(obj));