function create_node_with_relationship
Creates a new node in a Neo4j graph database and optionally establishes a relationship with an existing node in a single atomic operation.
/tf/active/vicechatdev/CDocs/db/db_operations.py
98 - 188
moderate
Purpose
This function provides an atomic operation to create a node and immediately connect it to another node via a relationship. It handles property sanitization, automatic UID generation, timestamp creation, and supports bidirectional relationships. This is useful for maintaining referential integrity when creating related entities in a graph database, avoiding the need for separate create and link operations.
Source Code
def create_node_with_relationship(
label: str,
properties: Dict[str, Any],
to_node_uid: str = None,
relationship_type: str = None,
relationship_direction: str = "OUTGOING",
relationship_properties: Dict[str, Any] = None
) -> Optional[Dict[str, Any]]:
"""
Create a node and immediately establish a relationship with another node.
Parameters
----------
label : str
The node label for the new node
properties : dict
Properties for the new node
to_node_uid : str
UID of the node to create a relationship with
relationship_type : str
Type of relationship to create
relationship_direction : str
Direction of relationship: "OUTGOING" (new node -> existing node)
or "INCOMING" (existing node -> new node)
relationship_properties : dict
Properties for the relationship
Returns
-------
dict
The created node properties
"""
try:
# Sanitize properties first
properties = _sanitize_properties(properties)
# Generate a unique ID if not provided
if 'UID' not in properties:
properties['UID'] = str(uuid.uuid4())
# Add creation timestamp if not provided
if 'createdDate' not in properties:
properties['createdDate'] = datetime.now()
# If no relationship needed, just create the node
if not to_node_uid or not relationship_type:
return create_node(label, properties)
# Set relationship direction in query
if relationship_direction == "OUTGOING":
rel_pattern = "-[r:%s]->(n2)" % relationship_type
else:
rel_pattern = "<-[r:%s]-(n2)" % relationship_type
# Build the query with relationship creation
query = f"""
MATCH (n2 {{UID: $to_node_uid}})
CREATE (n:{label} $node_props) {rel_pattern}
"""
# Add relationship properties if provided
if relationship_properties:
rel_props_str = " {" + ", ".join([f"{k}: ${k}" for k in relationship_properties.keys()]) + "}"
query = query.replace(f"r:{relationship_type}", f"r:{relationship_type}{rel_props_str}")
query += " RETURN n"
# Prepare parameters
params = {
"to_node_uid": to_node_uid,
"node_props": properties
}
# Add relationship properties to params
if relationship_properties:
params.update(relationship_properties)
# Execute the query
result = run_query(query, params)
# Return created node properties
if result and 'n' in result[0]:
return dict(result[0]['n'])
return properties
except Exception as e:
logger.error(f"Error creating node with relationship: {str(e)}")
import traceback
logger.error(traceback.format_exc())
return None
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
label |
str | - | positional_or_keyword |
properties |
Dict[str, Any] | - | positional_or_keyword |
to_node_uid |
str | None | positional_or_keyword |
relationship_type |
str | None | positional_or_keyword |
relationship_direction |
str | 'OUTGOING' | positional_or_keyword |
relationship_properties |
Dict[str, Any] | None | positional_or_keyword |
Parameter Details
label: The node label (type) for the new node being created. This is a string that categorizes the node in the Neo4j graph (e.g., 'Person', 'Document', 'Event').
properties: A dictionary containing the properties (attributes) to assign to the new node. Keys are property names and values are property values. If 'UID' is not provided, one will be auto-generated. If 'createdDate' is not provided, current timestamp will be added.
to_node_uid: Optional. The unique identifier (UID) of an existing node to create a relationship with. If None or not provided, only the node is created without any relationship.
relationship_type: Optional. The type/label of the relationship to create between the new node and the existing node (e.g., 'KNOWS', 'CREATED_BY', 'BELONGS_TO'). Required if to_node_uid is provided.
relationship_direction: Direction of the relationship. 'OUTGOING' means the new node points to the existing node (new)-[rel]->(existing). 'INCOMING' means the existing node points to the new node (existing)-[rel]->(new). Defaults to 'OUTGOING'.
relationship_properties: Optional. A dictionary of properties to attach to the relationship itself. Keys are property names and values are property values (e.g., {'since': '2024', 'weight': 0.8}).
Return Value
Type: Optional[Dict[str, Any]]
Returns a dictionary containing the properties of the created node if successful, including any auto-generated fields like UID and createdDate. Returns None if an error occurs during creation. The dictionary keys are property names and values are the corresponding property values.
Dependencies
logginguuidtypingdatetimeneo4jtraceback
Required Imports
import logging
import uuid
from typing import Dict, Any, Optional
from datetime import datetime
from neo4j import Driver
Conditional/Optional Imports
These imports are only needed under specific conditions:
import traceback
Condition: Used internally for error logging when exceptions occur
Required (conditional)Usage Example
# Create a new Comment node and link it to an existing Post node
comment_props = {
'text': 'Great article!',
'author': 'John Doe'
}
# Create comment with OUTGOING relationship to post
comment = create_node_with_relationship(
label='Comment',
properties=comment_props,
to_node_uid='post-uuid-12345',
relationship_type='COMMENTED_ON',
relationship_direction='OUTGOING',
relationship_properties={'timestamp': datetime.now(), 'rating': 5}
)
if comment:
print(f"Created comment with UID: {comment['UID']}")
else:
print("Failed to create comment")
# Create a node without relationship (fallback behavior)
standalone_node = create_node_with_relationship(
label='Tag',
properties={'name': 'python', 'category': 'programming'}
)
Best Practices
- Always provide a to_node_uid and relationship_type together; if one is provided without the other, the function will fall back to creating only the node
- Ensure the target node (to_node_uid) exists in the database before calling this function, as the query will fail if it doesn't
- Use meaningful relationship_type names that clearly describe the relationship (e.g., 'CREATED_BY', 'BELONGS_TO', 'RELATED_TO')
- The function automatically generates a UID and createdDate if not provided, so avoid manually setting these unless you have a specific reason
- Handle the None return value to detect and respond to creation failures
- Use relationship_properties to add metadata about the relationship (timestamps, weights, etc.) rather than storing this data on nodes
- Be aware that this is an atomic operation - if the relationship creation fails, the entire operation fails and no node is created
- The _sanitize_properties function is called internally, so ensure your properties are compatible with Neo4j data types
- Consider using relationship_direction='INCOMING' when the semantic meaning is that the existing node should point to the new node
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function create_node_and_ensure_relationships 89.0% similar
-
function create_node 69.3% similar
-
function create_relationship 69.0% similar
-
function create_node_with_uid 67.9% similar
-
function create_relationship_with_retry 66.1% similar