🔍 Code Extractor

function create_node_with_relationship

Maturity: 76

Creates a new node in a Neo4j graph database and optionally establishes a relationship with an existing node in a single atomic operation.

File:
/tf/active/vicechatdev/CDocs/db/db_operations.py
Lines:
98 - 188
Complexity:
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

  • logging
  • uuid
  • typing
  • datetime
  • neo4j
  • traceback

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

Similar Components

AI-powered semantic similarity - components with related functionality:

  • function create_node_and_ensure_relationships 89.0% similar

    Creates a new node in a Neo4j graph database and establishes multiple relationships to existing nodes within a single atomic transaction.

    From: /tf/active/vicechatdev/CDocs/db/db_operations.py
  • function create_node 69.3% similar

    Creates a node in a Neo4j graph database with a specified label and properties, automatically generating a unique ID and timestamp if not provided.

    From: /tf/active/vicechatdev/CDocs/db/db_operations.py
  • function create_relationship 69.0% similar

    Creates a directed relationship between two Neo4j graph database nodes identified by their UIDs, with optional properties attached to the relationship.

    From: /tf/active/vicechatdev/CDocs/db/db_operations.py
  • function create_node_with_uid 67.9% similar

    Creates a new node in a Neo4j graph database with a specified UID, label, and properties, automatically adding a creation timestamp if not provided.

    From: /tf/active/vicechatdev/CDocs/db/db_operations.py
  • function create_relationship_with_retry 66.1% similar

    Creates a relationship between two nodes in a graph database with automatic retry logic that handles case-insensitive UID matching when the initial attempt fails.

    From: /tf/active/vicechatdev/CDocs/utils/uid_helper.py
← Back to Browse