Formatting output of apoc.convert.toTree

Hi, i have to retrieve a hierarchical json for displaying a force directed tree in d3.js but i can't figure out how to format output data of apoc.convert.toTree:

MATCH path = (a:Asset)-[:HAS_ASSET *0..]->(b:Asset)
WHERE id(a)=59760
WITH collect(path) AS paths
CALL apoc.convert.toTree(paths, true, {
  nodes: {Asset: ['type']},
  rels:  {has_asset: ['type']}
})
YIELD value
RETURN value
  • List item

My first issue is, config option in .toTree procedure doesn't seem to work as expected, it returns always all the properties even if in try to set whitelist or blacklist.

  • List item

Second issue, i want to format the "value" at the end (for formatting dates with apoc.date.format, lowercase some value etc..) but i failed at formatting nested values.
Normally i format my output with a collect like this:

WITH collect(DISTINCT {id: id(n), type: toLower(n.type), value: n.value, firstSeen: apoc.date.format(n.firstSeen.epochMillis, "ms", "yyyy-MM-dd HH:mm:ss"), lastSeen: apoc.date.format(n.lastSeen.epochMillis, "ms", "yyyy-MM-dd HH:mm:ss")}) AS nodes,

Is my actual output:

{
  "lastSeen": {
    "year": {
      "low": 2021,
      "high": 0
    },
    "month": {
      "low": 6,
      "high": 0
    },
    "day": {
      "low": 28,
      "high": 0
    },
    "hour": {
      "low": 18,
      "high": 0
    },
    "minute": {
      "low": 7,
      "high": 0
    },
    "second": {
      "low": 21,
      "high": 0
    },
    "nanosecond": {
      "low": 802251704,
      "high": 0
    },
    "timeZoneOffsetSeconds": {
      "low": 0,
      "high": 0
    },
    "timeZoneId": null
  },
  "firstSeen": {
    "year": {
      "low": 2021,
      "high": 0
    },
    "month": {
      "low": 6,
      "high": 0
    },
    "day": {
      "low": 28,
      "high": 0
    },
    "hour": {
      "low": 18,
      "high": 0
    },
    "minute": {
      "low": 7,
      "high": 0
    },
    "second": {
      "low": 21,
      "high": 0
    },
    "nanosecond": {
      "low": 802251704,
      "high": 0
    },
    "timeZoneOffsetSeconds": {
      "low": 0,
      "high": 0
    },
    "timeZoneId": null
  },
  "_type": "Domain:Asset",
  "update": false,
  "uniqId": "34",
  "_id": {
    "low": 59760,
    "high": 0
  },
  "type": "Domain",
  "toUpdateDate": {
    "year": {
      "low": 2021,
      "high": 0
    },
    "month": {
      "low": 6,
      "high": 0
    },
    "day": {
      "low": 29,
      "high": 0
    },
    "hour": {
      "low": 18,
      "high": 0
    },
    "minute": {
      "low": 7,
      "high": 0
    },
    "second": {
      "low": 21,
      "high": 0
    },
    "nanosecond": {
      "low": 802544162,
      "high": 0
    },
    "timeZoneOffsetSeconds": {
      "low": 0,
      "high": 0
    },
    "timeZoneId": null
  },
  "value": "react.org",
  "has_asset": [
    {
      "lastSeen": {
        "year": {
          "low": 2021,
          "high": 0
        },
        "month": {
          "low": 6,
          "high": 0
        },
        "day": {
          "low": 28,
          "high": 0
        },
        "hour": {
          "low": 18,
          "high": 0
        },
        "minute": {
          "low": 7,
          "high": 0
        },
        "second": {
          "low": 46,
          "high": 0
        },
        "nanosecond": {
          "low": 274650496,
          "high": 0
        },
        "timeZoneOffsetSeconds": {
          "low": 0,
          "high": 0
        },
        "timeZoneId": null
      },
      "firstSeen": {
        "year": {
          "low": 2021,
          "high": 0
        },
        "month": {
          "low": 6,
          "high": 0
        },
        "day": {
          "low": 28,
          "high": 0
        },
        "hour": {
          "low": 18,
          "high": 0
        },
        "minute": {
          "low": 7,
          "high": 0
        },
        "second": {
          "low": 46,
          "high": 0
        },
        "nanosecond": {
          "low": 274650496,
          "high": 0
        },
        "timeZoneOffsetSeconds": {
          "low": 0,
          "high": 0
        },
        "timeZoneId": null
      },
      "_type": "Asset:Subdomain",
      "update": false,
      "uniqId": "45",
      "_id": {
        "low": 59813,
        "high": 0
      },
      "type": "Subdomain",
      "toUpdateDate": {
        "year": {
          "low": 2021,
          "high": 0
        },
        "month": {
          "low": 6,
          "high": 0
        },
        "day": {
          "low": 29,
          "high": 0
        },
        "hour": {
          "low": 6,
          "high": 0
        },
        "minute": {
          "low": 7,
          "high": 0
        },
        "second": {
          "low": 46,
          "high": 0
        },
        "nanosecond": {
          "low": 274987063,
          "high": 0
        },
        "timeZoneOffsetSeconds": {
          "low": 0,
          "high": 0
        },
        "timeZoneId": null
      }
    }
  ]
}

And here is the desired output:

{
    "lastSeen": "2021-06-28 18:07:21",
    "firstSeen": "2021-06-28 18:07:21",
    "_id": {
      "low": 59760,
      "high": 0
    },
    "type": "Domain",
    "value": "react.org",
    "has_asset": [
      {
        "lastSeen": "2021-06-28 18:07:21",
        "firstSeen": "2021-06-28 18:07:21",
        "_id": {
          "low": 59813,
          "high": 0
        },
        "type": "Subdomain",
        "value": "www.react.org",
      }
    ]
}

I don't know in advance the depth of the tree.

  • neo4j version: 4.3.1
  • driver: neo4j-javascript-driver

Thank you for your help!

Try this:

WITH collect(DISTINCT {id: id(n), type: toLower(n.type), value: n.value, firstSeen: apoc.date.format(n.firstSeen.epochMillis, "ms", "yyyy-MM-dd HH:mm:ss"), lastSeen: apoc.date.format(n.lastSeen.epochMillis, "ms", "yyyy-MM-dd HH:mm:ss")}) AS nodes
RETURN apoc.convert.toJson(nodes)

Sorry but i need to have a tree structure like in my desired output example, i search a solution to formatting nodes in path before of after to send it in apoc.convert.toTree() procedure. And nested has_asset array's have to be formatted too.