Occasional Blog

Don't feed them after midnight

August 02, 2020

Below I describe some techniques I have found for querying nested data that does not fit well in a traditional relational database. These are specific to the Gremlin query language and compatible databases.

Setup for connecting to Neptune (VPC restriction but no IAM)

const gremlin = require("gremlin")
const { Graph } = gremlin.structure
const { DriverRemoteConnection } = gremlin.driver
const graph = new Graph()

const remoteConnection = new DriverRemoteConnection(
  `wss://neptune-url:8182/gremlin`,
  {}
)
const connection = graph.traversal().withRemote(remoteConnection)

All of the following use the connection object described above.
I'll use the Greek mythos as example queries.

Access to gremlin functions in javascript

const { id } = gremlin.process.t
const { in_, out, inE, properties } = gremlin.process.statics
const { within } = gremlin.process.P
  • process.t provides native attributes like id and label
  • process.statics provides querying functions such as in and out for following edges or retrieving properties
  • process.P provides comparators like between, eq, within or gt

Conditional Function composition

const countChildren = baseQuery => {
  /**
   *  [titan | Kronos] -> child -> [god | Zeus]
   *  [titan | Hyperion] -> child -> [titan | Helios]
   *  [titan | Crius]
   * BECOMES
   *  [titan | Kronos] -> child -> [god | Zeus]
   *  [titan | Hyperion] -> child -> [titan | Helios]
   */
  return baseQuery.where(
    outE("child")
      .count()
      .is(gt(0))
  )
}
const fetchChildren = baseQuery => {
  return baseQuery
    .project("name", "children")
    .by("name")
    .by(
      outE("child")
        .inV()
        .valueMap()
        .fold()
    )
}
let baseQuery = connection.V().hasLabel("titan")

if (has_children) {
  baseQuery = countChildren(baseQuery)
}

if (get_children) {
  baseQuery = fetchChildren(baseQuery)
}

const result = await baseQuery.toList()

This example returns all Titans who have children, as well as a list of their children.

Subset of this below

[
  Map {
    'name' => 'Hyperion',
    'children' => [ Map { 'name' => [ 'Helios' ] } ]
  },
  Map {
    'name' => 'Kronos',
    'children' => [ Map { 'name' => [ 'Zeus' ] } ]
  }
]

End

Hopefully this will help someone else working with gremlin and AWS Neptune


Daniel Betteridge lives and works in London
I work to solve business problems, usually with as little code as possible
Follow me on Twitter

© 2022