Skip to content

3.1 The simplest join — id-match (Person → HubSpot contact by email)

MATCH (p:Person {name:'Ada Lovelace'})-[:HAS_HUBSPOT_CONTACT]->(c:HubSpotContact)
RETURN c.company, c.jobtitle

Means: “What does HubSpot say about Ada?”

How it executes:

  • Probe — bind p: find the persisted Person named Ada (scoped to you), read her primaryEmail — say ada@example.com. That email is the key.
  • Fetch — call the contactsByEmail producer once with ['ada@example.com']. It returns Ada’s HubSpot contact record { email, company, jobtitle, … }.
  • Materialize — make a transient (:HubSpotContact:Virtual { … }) and an edge (ada)-[:HAS_HUBSPOT_CONTACT]->(c), because the record’s email (recordKeyField) equals Ada’s primaryEmail (keyField).
  • Run — your RETURN c.company, c.jobtitle reads the transient node. Done.
  • Roll back — the contact node disappears.

Declared: a HubSpotContact type with one virtualJoins entry { anchorLabel: Person, relationship: HAS_HUBSPOT_CONTACT, keyField: primaryEmail, recordKeyField: email, producer: contactsByEmail }, and a producers/ entry contactsByEmail (kind: remote).

This is the id-match shape: the anchor is a real domain node and the join links by a shared value (email). Contrast with the bridge shape (§3.2), where the anchor is itself an external identity node.