Skip to main content

Connect Records

Relationships are the connections that link records together, creating a graph structure. They have a type (a string label you define), a direction, and optional user-defined edge properties.

RushDB has two categories of relationships:

TypeCreated byDescription
__RUSHDB__RELATION__DEFAULT__Imports, and attach without a typeLinks parent → child records in nested JSON
Custom ("STARS_IN", "DIRECTED_BY", etc.)YouDomain-specific, manually created

Attach Records​

db.records.attach()

# Single target
db.records.attach(
source=movie,
target=actor,
options={"type": "STARS_IN", "direction": "out", "properties": {"role": "lead"}}
)

# One-to-many (target list)
db.records.attach(
source=movie,
target=[actor1, actor2, actor3],
options={"type": "STARS_IN"}
)

Detach Records​

db.records.detach()

db.records.detach(
source=movie,
target=actor,
options={"typeOrTypes": "STARS_IN"}
# Omit "typeOrTypes" to detach every relationship type
)

Without typeOrTypes, detach removes relationships of every type; without direction ("in" or "out"), it removes them pointing either way. detach can't run inside a transaction.


List Relationships​

db.relationships.find()

# Relationship search: where filters edge type/properties
relationships = db.relationships.find(
search_query={
"source": {"labels": ["MOVIE"], "where": {"title": "Inception"}},
"target": {"labels": ["ACTOR"], "where": {"country": "USA"}},
"where": {"type": "STARS_IN", "role": "lead"}
}
)

# With pagination
page = db.relationships.find(
search_query={"source": {"labels": ["MOVIE"]}},
pagination={"limit": 50, "skip": 0}
)

db.relationships.find().where is edge-scoped. Use source and target for record predicates. To filter records by traversing relationships, use db.records.find() with $relation as shown below.

Edge properties are stored directly on relationship edges. They are filterable through relationships.find() and summarized in schema relationship sections, but they are not record properties and cannot be vector or text indexed. See Relationship Properties for storage semantics, the full operator set, and modeling guidance.


Direction Reference​

directionGraph pattern
out(source) -[:TYPE]-> (target)
in(source) <-[:TYPE]- (target)

Search by Relationship​

Use $relation inside a where clause to filter records through their graph connections. The nested key is the label of the related record; $relation constrains which relationship edge to follow.

Any relationship type​

Omit $relation to traverse any edge connecting the two labels:

# Find MOVIEs connected to an ACTOR named "Timothée Chalamet" — any relationship type
result = db.records.find({
"labels": ["MOVIE"],
"where": {
"ACTOR": {
"name": "Timothée Chalamet"
}
}
})

Filter by relationship type​

Pass $relation as a string to restrict traversal to a specific relationship type. This produces a direction-agnostic Cypher pattern (-[:TYPE]-) that matches the edge regardless of its stored direction — use the full object form (below) to also constrain direction:

result = db.records.find({
"labels": ["MOVIE"],
"where": {
"ACTOR": {
"$relation": "STARS_IN",
"country": "USA"
}
}
})

Filter by relationship type and direction​

Use the full object form when direction matters:

FieldTypeDescription
typestringRelationship type label
direction"in" | "out"Edge direction relative to the root record
# Find MOVIEs where an ACTOR is connected via an incoming STARS_IN edge
# i.e. (ACTOR) -[:STARS_IN]-> (MOVIE)
result = db.records.find({
"labels": ["MOVIE"],
"where": {
"ACTOR": {
"$relation": {"type": "STARS_IN", "direction": "in"},
"country": "USA"
}
}
})

Multi-hop traversal​

Nest $relation filters to traverse multiple relationship levels in a single query:

# Companies → Engineering departments → projects with budget over 10k
result = db.records.find({
"labels": ["COMPANY"],
"where": {
"name": "Acme Corp",
"DEPARTMENT": {
"$relation": "HAS_DEPARTMENT",
"name": "Engineering",
"PROJECT": {
"$relation": "HAS_PROJECT",
"budget": {"$gte": 10000}
}
}
}
})

→ For the full operator reference including $alias, $id, and logical grouping, see Where Operators — Relationship Queries.


In a Transaction​

tx = db.tx.begin()
try:
movie = db.records.create(
label="MOVIE", data={"title": "Dune"}, transaction=tx
)
actor = db.records.create(
label="ACTOR", data={"name": "Timothée Chalamet"}, transaction=tx
)
db.records.attach(
source=movie,
target=actor,
options={"type": "STARS_IN"},
transaction=tx
)
tx.commit()
except Exception:
tx.rollback()
raise

Via Record Instance​

# Record instance methods — equivalent to db.records.attach/detach
movie.attach(
target=actor,
options={"type": "STARS_IN", "direction": "out"}
)

movie.detach(
target=actor,
options={"typeOrTypes": "STARS_IN"}
)

See also​

  • Bulk Relationships — connect/disconnect many records at once by key match or many-to-many
  • Import Data — nested JSON auto-creates relationships
  • Transactions — ACID guarantees for multi-step operations