0
\$\begingroup\$

I have an array of leaf node (child nodes) and I want to find the parent nodes to them. I have a tree of approx 44000 nodes.

the leaf node array for this example is

const leafNodes = ["13020101",
  "13020102",
  "13020103"]

When I run my code I get the following node (which is working):

const allNodesNeededToGenerateANodeTree = [
    "13000000",
    "13020000",
    "13020100",
    "13020101",
    "13020102",
    "13020103",
]

I would like to know how I can make my code more efficient as now I use multiple forEach loops to generate

  1. the segment - level 1
  2. the main group - level 2
  3. the group - level 3
  4. commodity class - level 4 (which are the leaf nodes I send in as input)

My code:

Eclass.find({}, "codedName preferredName").sort({ codedName: 1 })
  .then(data => {
    // find segment nodes
    leafNodes.forEach(leafNode => {
      data.forEach(item => {
        if (item.codedName !== undefined && !nodes.includes(item.codedName) && leafNode.substring(0, 2) === item.codedName.substring(0, 2) && item.codedName.substring(2, 4) === "00") {
          nodes.push(item.codedName);
        }
      });
    });
    return data;
  })
  .then(data => {
    // find main group nodes
    leafNodes.forEach(leafNode => {
      data.forEach(item => {
        if (item.codedName !== undefined && !nodes.includes(item.codedName) && leafNode.substring(0, 4) === item.codedName.substring(0, 4) && item.codedName.substring(4, 6) === "00") {
          nodes.push(item.codedName);
        }
      });
    });
    return data;
  })
  .then(data => {
    // find group nodes
    leafNodes.forEach(leafNode => {
      data.forEach(item => {
        if (item.codedName !== undefined && !nodes.includes(item.codedName) && leafNode.substring(0, 6) === item.codedName.substring(0, 6) && item.codedName.substring(6, 8) === "00") {
          nodes.push(item.codedName);
        }
      });
    });
    // put the leaf nodes (commodity classes) into the nodes array
    const allNodesNeededToGenerateANodeTree = [...nodes, ...leafNodes].sort();
    console.log(allNodesNeededToGenerateANodeTree);
    res.status(200).json(allNodesNeededToGenerateANodeTree);
    return allNodesNeededToGenerateANodeTree;
  });

example "data:

[{
  "id": "13000000",
  "children": [{
    "id": "13010000",
    "children": [{
      "id": "13010100",
      "children": [{
        "id": "13010190",
        "children": [],
        "name": "13010190 Feasibility analysis (unspecified)"
      }],
      "name": "130101 Feasibility analysis"
    }, {
      "id": "13010200",
      "children": [{
        "id": "13010290",
        "children": [],
        "name": "13010290 Product definition (concept definition, unspecified)"
      }],
      "name": "130102 Product definition (concept definition)"
    }, {
      "id": "13010300",
      "children": [{
        "id": "13010301",
        "children": [],
        "name": "13010301 Function definition (specification total product level)"
      }, {
        "id": "13010302",
        "children": [],
        "name": "13010302 Function definition (specification system level)"
      }, {
        "id": "13010303",
        "children": [],
        "name": "13010303 Function definition (specification part level)"
      }, {
        "id": "13010390",
        "children": [],
        "name": "13010390 Function definition (unspecified)"
      }],
      "name": "130103 Function definition"
    }, {
      "id": "13010400",
      "children": [{
        "id": "13010490",
        "children": [],
        "name": "13010490 Concept interpretation (unspecified)"
      }],
      "name": "130104 Concept interpretation"
    }, {
      "id": "13010500",
      "children": [{
        "id": "13010590",
        "children": [],
        "name": "13010590 Patent and licence (concept development, unspecified)"
      }],
      "name": "130105 Patent and licence (concept development)"
    }, {
      "id": "13010600",
      "children": [{
        "id": "13010690",
        "children": [],
        "name": "13010690 Package (concept development, unspecified)"
      }],
      "name": "130106 Package (concept development)"
    }, {
      "id": "13010700",
      "children": [{
        "id": "13010790",
        "children": [],
        "name": "13010790 Judgment (concept development, unspecified)"
      }],
      "name": "130107 Judgment (concept development)"
    }, {
      "id": "13010800",
      "children": [{
        "id": "13010890",
        "children": [],
        "name": "13010890 Physics (concept development, unspecified)"
      }],
      "name": "130108 Physics (concept development)"
    }, {
      "id": "13010900",
      "children": [{
        "id": "13010990",
        "children": [],
        "name": "13010990 Product optimization (concept development, unspecified)"
      }],
      "name": "130109 Product optimization (concept development)"
    }, {
      "id": "13011000",
      "children": [{
        "id": "13011090",
        "children": [],
        "name": "13011090 Visual concept (unspecified)"
      }],
      "name": "130110 Visual concept"
    }, {
      "id": "13011100",
      "children": [{
        "id": "13011190",
        "children": [],
        "name": "13011190 Product surveying (concept development, unspecified)"
      }],
      "name": "130111 Product surveying (concept development)"
    }, {
      "id": "13019000",
      "children": [{
        "id": "13019090",
        "children": [],
        "name": "13019090 Concept development (Other, unspecified)"
      }],
      "name": "130190 Concept development (Other)"
    }],
    "name": "1301 Concept development"
  }, {
    "id": "13020000",
    "children": [{
      "id": "13020100",
      "children": [{
        "id": "13020101",
        "children": [],
        "name": "13020101 Specification performance (general product construction)"
      }, {
        "id": "13020102",
        "children": [],
        "name": "13020102 Constructional performance (general product construction)"
      }, {
        "id": "13020103",
        "children": [],
        "name": "13020103 Drawing setting-up, STRAK (general product construction)"
      }, {
        "id": "13020104",
        "children": [],
        "name": "13020104 Tolerance Testing (general product construction)"
      }, {
        "id": "13020105",
        "children": [],
        "name": "13020105 Constructional consequence analysis (general product construction)"
      }, {
        "id": "13020106",
        "children": [],
        "name": "13020106 Calculation, Simulation (general product construction)"
      }, {
        "id": "13020107",
        "children": [],
        "name": "13020107 Verification, Validation (general product construction)"
      }, {
        "id": "13020190",
        "children": [],
        "name": "13020190 General product construction (unspecified)"
      }],
      "name": "130201 General product construction"
    }, {
      "id": "13020200",
      "children": [{
        "id": "13020290",
        "children": [],
        "name": "13020290 Construction product acoustics (unspecified)"
      }],
      "name": "130202 Construction product acoustics"
    }, {
      "id": "13029000",
      "children": [{
        "id": "13029090",
        "children": [],
        "name": "13029090 Construction (development activity)"
      }],
      "name": "130290 Mechanical construction (Other)"
    }],
    "name": "1302 Mechanical construction"
  }]
}]
\$\endgroup\$
  • \$\begingroup\$ If your ids are always structured as "<segment><main group><group><class>" you can determin the parents directly from the leaf id \$\endgroup\$ – TheGr8_Nik Feb 2 '18 at 14:59
  • \$\begingroup\$ @TheGr8_Nik I have thought about that, but do you have an idea of how to translate that to code? \$\endgroup\$ – Isak La Fleur Feb 2 '18 at 15:38
3
\$\begingroup\$

I will do something like this:

const leafNodes = ["13020101", "13020102", "13020103"];
var nodes = [];
for (const leafNode of leafNodes) {
  // Determins the parents
  //
  var segment   = leafNode.substr(0, 2).padEnd(8, '0');
  var mainGroup = leafNode.substr(0, 4).padEnd(8, '0');
  var group     = leafNode.substr(0, 6).padEnd(8, '0');

  // Add the parents in the nodes list
  //
  addNode(nodes, segment);
  addNode(nodes, mainGroup);
  addNode(nodes, group);
  addNode(nodes, leafNode);
};

nodes.sort();

console.log(nodes);

where the addNode function can be something like this:

function addNode(nodes, node) {
  // Check if the id is already present in nodes
  //
  var isAlreadyIn = nodes.indexOf(node) !== -1;

  // if not present
  //
  if (!isAlreadyIn) {
    // add the node
    //
    nodes.push(node);
  }
}
\$\endgroup\$
  • 1
    \$\begingroup\$ If you are just iterating an array you should use Array.forEach. Using Array.map as you do is just creating avoidable GC and allocation overheads. Even better in terms of performance and memory use for (const node of leafNodes) { \$\endgroup\$ – Blindman67 Feb 2 '18 at 17:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.