cancel
Showing results for 
Search instead for 
Did you mean: 

Join the community at Nodes 2022, our free virtual event on November 16 - 17.

Problems with complex object result in plugin

marc_roth
Node Clone

Hi folks,

I'm new to neo4j plugin development as until today I came through every task with cypher and apoc for the last nine years.
Anyway - right now I've got stuck mapping a response from neo4j within Java an iternate through the nested lists. My "pretty unpretty" code as followed is straight forward and should only loop through the nested lists and do some fancy recursive stuff on lowest level.
But I really can't figure it out how to map the first result from the database and iterate through all lists. Please let me know, if anyone can help me an this issue.

Kind regards,
Marc

package SDM.BOM;

import java.lang.RuntimeException;
import java.util.*;

import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Result;
import org.neo4j.procedure.Description;
import org.neo4j.procedure.Name;
import org.neo4j.procedure.UserFunction;

public class Procedures {

  @UserFunction
  @Description(
    "Returns relevant Component nodes for a given Component and ExportMapping."
  )
  public List<Object> getRelevantComponents(
    @Name("Component") Node component,
    @Name("ExportMapping") Node exportMapping
  ) {
    List<Object> relevantComponents;

    if (component == null || exportMapping == null) {
      return null;
    }

    Map<String, Object> params = new HashMap<>();
    params.put("exportMapping", exportMapping);


    try (
      Result result = component
        .getGraphDatabase()
        .execute(getRelevantComponents(), params)
    ) {
      relevantComponents = (List<Object>) result
        .next()
        .get("relevantComponent_maps");
    } catch (Exception e) {
      throw new RuntimeException(e.getMessage());
    }

    /*
    for (Object relevantComponent : relevantComponents) {
      for (Object pathItem :  relevantComponent.pathItems) {
        Node component_recursive = this.GetComponent(component, pathItem.componentTypes, pathItem.level, pathItem.number);
      }
    }
    */

    return relevantComponents;
  }

  private Node GetComponent(
    @Name("Component") Node component,
    @Name("ComponentTypes") List<ComponentType> componentTypes,
    String level,
    int sequence
  ) {
    // Node node = db.getNodeById(nodeId);
    Map<String, Object> params = new HashMap<>();
    params.put("component", component);
    params.put("componentTypes", componentTypes);

    try (
      Result result = component.getGraphDatabase().execute(getComponent(), params)
    ) {
      return (Node) result.next().get("component");
    } catch (Exception e) {
      throw new RuntimeException(e.getMessage());
    }
  }

  private String getRelevantComponents() {
    return (
      "with " +
      "  $exportMapping as exportMapping " +
      " " +
      "match (exportMapping)-[:hasRelevantComponent]->(relevantComponent:RelevantComponent) " +
      "match (relevantComponent)-[:nextPathItem*]->(pathItem:PathItem)-[:with]->(componentType:ComponentType) " +
      " " +
      "with distinct " +
      "  relevantComponent, " +
      "  pathItem, " +
      "  collect(distinct componentType{ " +
      "    id: id(componentType) " +
      "  }) as componentTypes " +
      " " +
      "with distinct " +
      "  relevantComponent, " +
      "  collect(distinct pathItem{ " +
      "    .level, " +
      "    .number, " +
      "    componentTypes " +
      "  }) as pathItems " +
      " " +
      "with " +
      "  collect(distinct relevantComponent{ " +
      "    id: id(relevantComponent), " +
      "    pathItems " +
      "  }) as relevantComponents " +
      " " +
      "return " +
      "  relevantComponents"
    );
  }

  private String getComponent() {
    return (
      "with $component as component " +
      " " +
      "call apoc.path.expandConfig(component, { " +
      "  bfs: true, " +
      "  sequence: 'Component,hasBOM>,BOM,hasBOMElement>', " +
      "  beginSequenceAtStart: true " +
      "}) yield path " +
      " " +
      "with " +
      "  component, " +
      "  length(path) / 2 + 1 as level, " +
      "  nodes(path)[-1] as component_master " +
      "where $level in ['..', '*', -1, '-1'] " +
      "  or level = apoc.convert.toInteger($level) " +
      " " +
      "match (component_master)-[:hasBOM]->(:BOM)-[hasBOMElement:hasBOMElement]->(component_child:Component)-[:hasComponentType]->(componentType:ComponentType) " +
      "where id(componentType) in [componentType_map in $componentType_maps | componentType_map.id] " +
      " " +
      "with " +
      "  level, " +
      "  component_master, " +
      "  hasBOMElement, " +
      "  component_child, " +
      "  componentType " +
      "order by coalesce(apoc.convert.toInteger(hasBOMElement.sequence)) " +
      " " +
      "with distinct " +
      "  level, " +
      "  component_master, " +
      "  collect(distinct component_child) as components, " +
      "  componentType " +
      " " +
      "unwind components as component " +
      " " +
      "with " +
      "  component, " +
      "  level, " +
      "  apoc.coll.indexOf(components, component) + 1 as number " +
      "where number = apoc.convert.toInteger($number) " +
      " " +
      "return " +
      "  component"
    );
  }
}

1 ACCEPTED SOLUTION

Hi Michael,

I just put some efforts into it. I can iterate through all nested objects thanks to your hints using a for loop on a result map. Though I can't use any apoc functions inside the queries running the tests of the project. But I'll close this issue, as the problem is solved and open a new one (see here).

View solution in original post

6 REPLIES 6

Your result has already the right type.

What is the concrete issue you're having?

You can also use result.single()

First I've tried to populate some POJOs for the PathItems, Components, etc. but the result (though casted correctly) always resulted to null. Now, using some list of objects I simply don't know how to tell the neo4j API to push the results in those nested lists and iterate through them... maybe you can give me a hint therefore.

Those statements work well in browser? If they return null perhaps something is off in there?

Perhaps it would be easier to use a simpler example, here is e.g. what we do in APOC.

Hi Marc, did you try my suggestion from the APOC example?

Hi Michael,

yes, and beside I had a look at (almost) all apoc functions that are doing something similar, but unfortunately I've still stuck on the iterator.
By the way, the neo4j browser returns a result, so the query itself works fine.

Hi Michael,

I just put some efforts into it. I can iterate through all nested objects thanks to your hints using a for loop on a result map. Though I can't use any apoc functions inside the queries running the tests of the project. But I'll close this issue, as the problem is solved and open a new one (see here).