Switch apoc.convert.toTree to apoc.paths.toJsonTree

Hi,

I'm trying to switch from the deprecated method 'apoc.convert.toTree' to the new one 'apoc.paths.toJsonTree' but I don't really understand the result

Here is my request :

MATCH path=(:ADEO_ConceptScheme {code:"http://opus-adeo/CONCEPT_SCHEME/generated_code_0"})<-[:TOP_CONCEPT_OF]-(:ADEO_Concept)<-[:BROADER*1..10]-(:ADEO_Concept)
              WITH COLLECT(path) as paths
              CALL apoc.paths.toJsonTree(paths)
              YIELD value
              RETURN value

Before the result was a beautiful tree :

{
  _type: "Node:ADEO_ConceptScheme",
  FR_title: "Features",
  _id: 50,
  top_concept_of: [
    {
      broader: [
        {
          broader: [
            {
              broader._elementId: "5:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:6919785225501278260",
              code: "http://opus-adeo/concept/generated_code_0",
              _type: "Node:ADEO_Concept:ADEO_Feature",
              _id: 53,
              FR_prefLabel: "With 1 sliding door",
              _elementId: "4:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:53",
              broader._id: 6919785225501278260
            }
          ],
          broader._elementId: "5:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:1152925902653358132",
          code: "http://opus-adeo/concept/generated_code_3",
          _type: "Node:ADEO_Concept:ADEO_Feature",
          _id: 52,
          FR_prefLabel: "With 1 door",
          _elementId: "4:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:52",
          broader._id: 1152925902653358132
        }
      ],
      code: "http://opus-adeo/concept/generated_code_2",
      properties: "{}",
      top_concept_of._elementId: "5:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:1152927002164985907",
      _type: "Node:ADEO_Concept:ADEO_Feature",
      _id: 51,
      FR_prefLabel: "With doors",
      top_concept_of._id: 1152927002164985907,
      _elementId: "4:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:51"
    },
    {
      broader: [
        {
          broader: [
            {
              broader._elementId: "5:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:6919785225501278263",
              FR_altLabels: [],
              code: "http://opus-adeo/concept/generated_code_6",
              _type: "Node:ADEO_Concept:ADEO_Feature",
              _id: 56,
              FR_prefLabel: "Water resistant",
              _elementId: "4:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:56",
              broader._id: 6919785225501278263
            }
          ],
          broader._elementId: "5:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:1152925902653358135",
          code: "http://opus-adeo/concept/generated_code_5",
          _type: "Node:ADEO_Concept:ADEO_Feature",
          _id: 55,
          FR_prefLabel: "Waterproof",
          _elementId: "4:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:55",
          broader._id: 1152925902653358135
        }
      ],
      code: "http://opus-adeo/concept/generated_code_4",
      properties: "{}",
      top_concept_of._elementId: "5:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:1152927002164985910",
      _type: "Node:ADEO_Concept:ADEO_Feature",
      _id: 54,
      FR_prefLabel: "Water",
      top_concept_of._id: 1152927002164985910,
      _elementId: "4:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:54"
    }
  ],
  _elementId: "4:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:50",
  code: "http://opus-adeo/CONCEPT_SCHEME/generated_code_0"
}

With the new method I have something like that :

[{
  _type: "Node:ADEO_Concept:ADEO_Feature",
  _id: 51,
  FR_prefLabel: "With doors",
  top_concept_of: [
    {
      _type: "Node:ADEO_ConceptScheme",
      FR_title: "Features",
      _id: 50,
      top_concept_of._id: 1152927002164985907,
      _elementId: "4:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:50",
      code: "http://opus-adeo/CONCEPT_SCHEME/generated_code_0",
      top_concept_of._elementId: "5:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:1152927002164985907"
    }
  ],
  _elementId: "4:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:51",
  code: "http://opus-adeo/concept/generated_code_2",

},
{
  _type: "Node:ADEO_Concept:ADEO_Feature",
  FR_hiddenLabels: [],
  broader: [
    {
      FR_hiddenLabels: [],
      broader._elementId: "5:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:1152925902653358132",
      FR_altLabels: [],
      code: "http://opus-adeo/concept/generated_code_2",
      properties: "{}",
      _type: "Node:ADEO_Concept:ADEO_Feature",
      _id: 51,
      ontologyClass: "ADEO:Feature",
      ES_hiddenLabels: [],
      FR_prefLabel: "With doors",
      _elementId: "4:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:51",
      ES_altLabels: [],
      broader._id: 1152925902653358132
    }
  ],
  _id: 52,
  ontologyClass: "ADEO:Feature",
  ES_hiddenLabels: [],
  FR_prefLabel: "With 1 door",
  FR_altLabels: [],
  _elementId: "4:3a59f5e1-d597-45c2-97f2-e4e2d2fc9236:52",
  code: "http://opus-adeo/concept/generated_code_3",
  properties: "{}",
  ES_altLabels: []
},
{...}
]

So my question is, am I supposed to recreate the tree myself with this new method ?

This looks very odd. The second result doesn't look like the same as the original result. The second one is a list for one. Are the two result of running on the exact same data?

When I go through the example in the documentation using the same data and executing both procedures, the results are identical.

Can you provide test data?

You can run this to recreate my test case

UNWIND [{_id:39, properties:{code:"https://opus-adeo.poolparty.biz/COMMONTAXO/0", FR_title:"NatureOfProduct", ontologyClass:"ADEO:ConceptScheme"}}, {_id:41, properties:{ES_title:"Características", code:"http://opus-adeo/CONCEPT_SCHEME/generated_code_0", FR_title:"Features", ontologyClass:"ADEO:ConceptScheme"}}, {_id:49, properties:{code:"http://opus-adeo/CONCEPT_SCHEME/generated_code_1", FR_title:"Brands", ontologyClass:"ADEO:ConceptScheme"}}, {_id:51, properties:{code:"http://opus-adeo/CONCEPT_SCHEME/generated_code_2", FR_title:"Styles", ontologyClass:"ADEO:ConceptScheme"}}] AS row
CREATE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:Node:ADEO_ConceptScheme;
UNWIND [{_id:40, properties:{ES_hiddenLabels:[], FR_prefLabel:"Tool", code:"http://opus-adeo/concept/generated_code_1", ontologyClass:"ADEO:NatureOfProduct", ES_altLabels:[], FR_hiddenLabels:[], properties:"{}", ES_prefLabel:"Herramienta", FR_altLabels:[]}}] AS row
CREATE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:ADEO_NatureOfProduct:Node:ADEO_ProductSet:ADEO_Concept;
UNWIND [{_id:50, properties:{ES_hiddenLabels:[], FR_prefLabel:"Sensea", code:"http://opus-adeo/concept/generated_code_8", ontologyClass:"ADEO:Brand", ES_altLabels:[], FR_hiddenLabels:[], properties:"{}", FR_altLabels:[]}}] AS row
CREATE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:ADEO_Brand:Node:ADEO_Concept;
UNWIND [{_id:42, properties:{ES_hiddenLabels:[], FR_prefLabel:"With doors", code:"http://opus-adeo/concept/generated_code_2", ontologyClass:"ADEO:Feature", ES_altLabels:[], FR_hiddenLabels:[], properties:"{}", FR_altLabels:[]}}, {_id:43, properties:{ES_hiddenLabels:[], FR_prefLabel:"With 1 door", code:"http://opus-adeo/concept/generated_code_3", ontologyClass:"ADEO:Feature", ES_altLabels:[], FR_hiddenLabels:[], properties:"{}", FR_altLabels:[]}}, {_id:44, properties:{ES_hiddenLabels:[], FR_prefLabel:"With 1 sliding door", code:"http://opus-adeo/concept/generated_code_0", ontologyClass:"ADEO:Feature", ES_altLabels:[], FR_hiddenLabels:[], properties:"{}", FR_altLabels:[]}}, {_id:45, properties:{ES_hiddenLabels:[], FR_prefLabel:"Water", code:"http://opus-adeo/concept/generated_code_4", ontologyClass:"ADEO:Feature", ES_altLabels:[], FR_hiddenLabels:[], properties:"{}", FR_altLabels:[]}}, {_id:46, properties:{ES_hiddenLabels:[], FR_prefLabel:"Waterproof", code:"http://opus-adeo/concept/generated_code_5", ontologyClass:"ADEO:Feature", ES_altLabels:[], FR_hiddenLabels:[], properties:"{}", FR_altLabels:[]}}, {_id:47, properties:{ES_hiddenLabels:[], FR_prefLabel:"Water resistant", code:"http://opus-adeo/concept/generated_code_6", ontologyClass:"ADEO:Feature", ES_altLabels:[], FR_hiddenLabels:[], properties:"{}", FR_altLabels:[]}}, {_id:48, properties:{ES_hiddenLabels:[], FR_prefLabel:"Sliding", code:"http://opus-adeo/concept/generated_code_7", ontologyClass:"ADEO:Feature", ES_altLabels:[], FR_hiddenLabels:[], properties:"{}", FR_altLabels:[]}}] AS row
CREATE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:Node:ADEO_Feature:ADEO_Concept;
UNWIND [{start: {_id:40}, end: {_id:39}, properties:{}}] AS row
MATCH (start:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.start._id})
MATCH (end:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.end._id})
CREATE (start)-[r:TOP_CONCEPT_OF]->(end) SET r += row.properties;
UNWIND [{start: {_id:43}, end: {_id:42}, properties:{}}, {start: {_id:44}, end: {_id:43}, properties:{}}, {start: {_id:46}, end: {_id:45}, properties:{}}, {start: {_id:47}, end: {_id:46}, properties:{}}] AS row
MATCH (start:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.start._id})
MATCH (end:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.end._id})
CREATE (start)-[r:BROADER]->(end) SET r += row.properties;
UNWIND [{start: {_id:42}, end: {_id:41}, properties:{}}, {start: {_id:45}, end: {_id:41}, properties:{}}, {start: {_id:48}, end: {_id:41}, properties:{}}] AS row
MATCH (start:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.start._id})
MATCH (end:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.end._id})
CREATE (start)-[r:TOP_CONCEPT_OF]->(end) SET r += row.properties;
UNWIND [{start: {_id:50}, end: {_id:49}, properties:{}}] AS row
MATCH (start:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.start._id})
MATCH (end:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.end._id})
CREATE (start)-[r:TOP_CONCEPT_OF]->(end) SET r += row.properties;

Then run

MATCH path=(:ADEO_ConceptScheme {code:"http://opus-adeo/CONCEPT_SCHEME/generated_code_0"})<-[:TOP_CONCEPT_OF]-(:ADEO_Concept)<-[:BROADER*1..10]-(:ADEO_Concept)
              WITH COLLECT(path) as paths
              CALL apoc.convert.toTree(paths)
              YIELD value
              RETURN value

Or

MATCH path=(:ADEO_ConceptScheme {code:"http://opus-adeo/CONCEPT_SCHEME/generated_code_0"})<-[:TOP_CONCEPT_OF]-(:ADEO_Concept)<-[:BROADER*1..10]-(:ADEO_Concept)
              WITH COLLECT(path) as paths
              CALL apoc.paths.toJsonTree(paths)
              YIELD value
              RETURN value

To see the different results

I find it very confusing that the documentation states that paths.toJsonTree has been deprecated for convert.toTree, as it implies the former is a substitute for the latter. They don't seem to have similar behavior at all. Here is the documentation's summary of each:

toJsonTree:

Returns a stream of MAP values, representing the graph as a tree by traversing outgoing relationships.

toTree:

Returns a stream of MAP values, representing the given PATH values as a tree with at least one root.

One difference is that toJsonTree traverses outgoing relationships. This explained why the results had a different hierarchy. Also, the toJsonTree returns returns a list of subpaths. I even tried reversion the TOP_CONCEPT_OF relationships so the path had all outgoing relationships starting from the ADEO_Concept_scheme node, but I still got a list of segments, instead of the one hierarchical structure returned by toTree.

Sorry, I can't help with this. I guess you can continue using toTree until it is removed.