Neo4j backend
cvcdocdb.neo4j_graph exposes the persistent backend that stores graphs in
Neo4j. It supports the same core concepts as the in-memory backend while
adding database connectivity, foreign-key checks, and graph persistence.
Neo4jGraph — Full Neo4j driver integration layer for the DRM graph model.
Provides graph operations (insert, update, delete nodes and relations) with FK validation, cascade delete, and WeakNode parent propagation.
- class cvcdocdb.neo4j_graph.Neo4jGraph(url, user, password, database=None)[source]
Bases:
objectNeo4j-backed graph store for the DRM document representation model.
This class wraps the Neo4j Python driver and provides high-level operations for managing graph nodes and relations with foreign key validation, cascade delete strategies (CASCADE, RESTRICT, SET NULL), and WeakNode parent-child propagation.
Example
>>> graph = Neo4jGraph( ... url="bolt://localhost:7687", ... user="neo4j", ... password="secret", ... database="mydb", ... ) >>> doc = Node(pk={"doc": "DOC-001"}, main_label="Document") >>> graph.insertNode(doc, replace=True) >>> graph.close()
- Parameters:
- insertNode(node, insert_parent=True, update=False, replace=False, **kwargs)[source]
Insert a node into the Neo4j database.
For WeakNode instances, the parent node is inserted first if
insert_parent=True. String dependencies (dependenciesattribute) are automatically materialised asValornodes connected by typed edges.- Parameters:
node (Node) – The node to insert.
insert_parent (bool) – If the node is a WeakNode, insert its parent first. Defaults to True.
update (bool) – If True, MERGE the node and update attributes without deleting it. Use when adding new attributes to an existing node. Defaults to False.
replace (bool) – If True and the node already exists, delete it (with detach) and create a fresh one. The caller must recreate relations. Defaults to False.
kwargs (Any)
- Returns:
The Neo4j internal node id of the inserted node.
- Return type:
- deleteNode(node, propagation=False, detach=False, on_delete='cascade')[source]
Delete a node and optionally its connected subgraph.
Handles ON DELETE strategies, WeakNode cascade propagation, and FK index cleanup.
- Parameters:
node (Node) – The node to delete.
propagation (bool) – If True, recursively delete child nodes linked via edges with
_propagate=TRUE(used by WeakNode).detach (bool) – If True, use Neo4j
DETACH DELETEto remove the node and all connected edges.on_delete (str) – Deletion strategy —
"cascade"(default),"restrict", or"set_null".
- Returns:
True if the node was deleted, False if deletion was refused (e.g. RESTRICT with existing edges) or the node was not found.
- Return type:
- checkNode(node, **kwargs)[source]
Check if a node exists in the database.
Looks up the node by its
neo4j_idif set, otherwise searches bymain_labeland primary key.
- insertRelation(rel, update=False, replace=False, **kwargs)[source]
Insert a directed relation (edge) between two nodes.
Validates that both source and destination nodes exist before creating the edge (FK constraint).
- Parameters:
rel (Relation) – The relation to insert, containing source node, destination node, and relation type.
update (bool) – If True, MERGE the relation and update attributes without deleting it. Defaults to False.
replace (bool) – If True and the relation already exists, delete it and create a fresh one. Defaults to False.
kwargs (Any)
- Returns:
The Neo4j internal relation id of the inserted relation.
- Raises:
RuntimeError – If the source or destination node does not exist in the database (FK violation).
- Return type:
- create(migration, update=False, replace=False)[source]
Bulk import nodes and relations from a migration plan.
Iterates over the node and relation lists, inserting each with a progress bar. Uses
insertNodeandinsertRelationinternally.
- get_nodes()[source]
Alias for
get_node_ids()for backward compatibility.
- get_node_attrs(node_id)[source]
Return attributes stored for a node.
Unlike
NetworkXGraph, Neo4j never persists which properties form a node’s primary key —pkis a purely client-side concept applied at insert time viaNode(pk=...)and not stored as metadata on the node itself. Reading back an arbitrary node therefore always reportspk=Nonehere, signalling “not known” rather than guessing; seecvcdocdb.migration.migrate()for how a generic caller is expected to handle it.
- batch(write=True)[source]
Group multiple calls into a single Neo4j transaction, committing once at the end instead of once per call — substantially faster for bulk writes (see
cvcdocdb.migration.migrate()).insertNode/insertRelationalready reuseself._txwhen one is open instead of starting their own (see theinici/ nested-parent-insert handling above), andquery()/get_node_ids()do the same, so plain reads made inside this block run in the same transaction too — giving a consistent snapshot for the whole block instead of one read-committed view per call. This just opens that transaction from the outside and commits/rolls back once for the whole block. Nesting is safe — an innerbatch()call while one is already open is a no-op.- Parameters:
write (bool) – Accepted for interface symmetry with
NetworkXGraph.batch()(which uses it to skip an unnecessary resave when the block is read-only). Neo4j has no equivalent distinction worth making here — committing a transaction that made no writes is a no-op — so this is ignored.- Return type:
Iterator[None]
- get_dependency_value(node_id, relation_type)[source]
Return the
nameproperty of the node reachable via a single outgoing relation_type edge from node_id.Targeted single-hop Cypher query — never scans the whole graph.
- query(filter_dict=None, projection=None, sort=None, limit_val=None, params=None)[source]
Query nodes using MongoDB-style filters or execute Cypher.
Hybrid API — the first argument accepts either:
dict — MongoDB-style filter matching against
main_label(tested against the node’s real Neo4j labels, not a property — see module notes above) and node attributes. Supports the same operators asNetworkXGraph.query():$eq,$ne,$gt,$gte,$lt,$lte,$in,$nin,$exists,$regex,$contains, and the logical combinators$or,$and,$not.str — a Cypher query string (
MATCH,CREATE,DELETE,SET,RETURN,ORDER BY,LIMIT, aggregations, parameter substitution via$name).
For dict filters, each record is
{"node_id": <neo4j internal id>, "main_label": <first label>, "properties": {...}}— the same shapeNetworkXGraph.query()returns for dict filters, so client code is portable between the two backends without changes.For str (Cypher) queries, each record is a dict mapping return aliases to values. Node values are dicts with
labelsandpropertieskeys. Relation values are dicts withtype,start_node,end_node, andpropertieskeys. Primitive values are returned as-is.- Parameters:
filter_dict (Dict[str, Any] | str | None) – Filter dict for MongoDB-style queries, or Cypher string for Cypher-style queries.
projection (Dict[str, int] | None) – Dict of fields to include (1) or exclude (0). Applied to
propertiesfor dict filters; ignored for Cypher queries (useRETURNaliases instead).sort (Tuple[str, int] | None) – Tuple of
(field_name, direction)where direction is1(ascending) or-1(descending). Only used for dict filters; ignored for Cypher queries (useORDER BY).limit_val (int | None) – Maximum number of results. Only used for dict filters; ignored for Cypher queries (use
LIMIT).params (Dict[str, Any] | None) – Optional parameter dict for
$namesubstitution in Cypher queries. Ignored for dict filters.
- Returns:
A list of dicts, one per matching node (dict-style) or one per result record (Cypher-style).
- Return type:
Example
>>> # MongoDB-style >>> graph.query({"main_label": "Person", "age": {"$gt": 25}}) >>> # Cypher-style >>> graph.query("MATCH (n:Person) RETURN n LIMIT 5") >>> graph.query( ... "MATCH (n:Person {name: $name}) RETURN n", ... params={"name": "Alice"}, ... )
- create_group(strong_node, weak_nodes=None, weak_relations=None, **kwargs)[source]
Create a strong node together with its WeakNodes and WeakRelations atomically using a Neo4j transaction.
All operations run inside a single
begin_transaction. If any step fails the transaction is rolled back.- Parameters:
- Returns:
The Neo4j internal id of the
strong_node.- Raises:
RuntimeError – If any part of the group creation fails.
- Return type:
- init_propagation(background=False, progress_callback=None)[source]
Scan the backend graph and initialize propagation properties.
See GraphStore.init_propagation for details.
- enable_vector_index(property_name, dimensions, space='cosine', **kwargs)[source]
Neo4j backend does not support vector indexes.
- query_vector_index(property_name, vector, top_k=5)[source]
Neo4j backend does not support vector queries.
- get_subdocuments(strong_node)[source]
Return all subdocuments (WeakNodes) reachable from strong_node through
_propagateedges.Follows edges in their declared direction (parent → child) and returns every descendant WeakNode as a dict with
label,pk, andpropertieskeys.