🔍 Code Extractor

function create_node_with_relationship_v1

Maturity: 76

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

File:
/tf/active/vicechatdev/CDocs single class/db/db_operations.py
Lines:
75 - 162
Complexity:
moderate

Purpose

This function provides an atomic operation to create a node and link it to an existing node in Neo4j. It automatically generates a UID and creation timestamp if not provided, supports bidirectional relationships (OUTGOING or INCOMING), and allows properties on both the node and relationship. This is useful for maintaining referential integrity and reducing the number of database round-trips when creating connected graph structures.

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:
        # 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 Neo4j node label (type) for the new node being created. This is a string that categorizes the node (e.g., 'Person', 'Document', 'Event').

properties: A dictionary containing the properties (attributes) to assign to the new node. If 'UID' is not included, a UUID will be auto-generated. If 'createdDate' is not included, the current datetime will be added automatically.

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: Specifies the direction of the relationship. 'OUTGOING' means the new node points to the existing node (new->existing). 'INCOMING' means the existing node points to the new node (existing->new). Defaults to 'OUTGOING'.

relationship_properties: Optional. A dictionary of properties to attach to the relationship itself (e.g., {'since': '2023-01-01', 'weight': 0.8}). Can be None if no relationship properties are needed.

Return Value

Type: Optional[Dict[str, Any]]

Returns a dictionary containing the properties of the newly created node if successful, including any auto-generated fields like UID and createdDate. Returns None if an error occurs during node creation or relationship establishment. The dictionary keys correspond to the node's property names and values are the property values.

Dependencies

  • logging
  • uuid
  • typing
  • datetime
  • neo4j
  • traceback
  • CDocs.db
  • CDocs.db.schema_manager

Required Imports

import logging
import uuid
from typing import Dict, Any, Optional
from datetime import datetime
from neo4j import Driver, Session, Transaction, Record
from neo4j.exceptions import ServiceUnavailable, ClientError
from CDocs.db import get_driver
from CDocs.db.schema_manager import NodeLabels, RelTypes

Conditional/Optional Imports

These imports are only needed under specific conditions:

import traceback

Condition: only used in exception handling for detailed error logging

Required (conditional)

Usage Example

# Create a new Document node linked to an existing User node
user_uid = 'user-123-abc'

# Example 1: Create node with outgoing relationship
doc_properties = {
    'title': 'Project Proposal',
    'content': 'This is the proposal content',
    'status': 'draft'
}

new_doc = create_node_with_relationship(
    label='Document',
    properties=doc_properties,
    to_node_uid=user_uid,
    relationship_type='CREATED_BY',
    relationship_direction='OUTGOING',
    relationship_properties={'timestamp': datetime.now(), 'role': 'author'}
)

if new_doc:
    print(f"Created document with UID: {new_doc['UID']}")

# Example 2: Create node without relationship
standalone_node = create_node_with_relationship(
    label='Tag',
    properties={'name': 'important', 'color': 'red'}
)

# Example 3: Create node with incoming relationship
comment_props = {'text': 'Great work!', 'rating': 5}
comment = create_node_with_relationship(
    label='Comment',
    properties=comment_props,
    to_node_uid=doc_properties['UID'],
    relationship_type='COMMENTED_ON',
    relationship_direction='INCOMING'
)

Best Practices

  • Always provide both to_node_uid and relationship_type together, or neither. Providing only one will result in just creating a node without a relationship.
  • Ensure the target node (to_node_uid) exists in the database before calling this function, as the query will fail if it doesn't match any existing node.
  • Use meaningful relationship_type names that follow Neo4j conventions (typically UPPERCASE_WITH_UNDERSCORES).
  • Be aware that this function auto-generates UID and createdDate if not provided in properties, which may override your intended values if you're not careful.
  • Handle the None return value appropriately, as it indicates an error occurred during the operation.
  • Consider wrapping this function call in a try-except block for additional error handling at the application level.
  • The function uses string formatting for Cypher query construction, which is generally safe here but be cautious about the relationship_type parameter to avoid injection issues.
  • Relationship properties are merged into the query parameters, so avoid key collisions between relationship_properties and other parameters like 'to_node_uid' or 'node_props'.
  • The function depends on external run_query() and create_node() functions that must be properly implemented and available in scope.

Similar Components

AI-powered semantic similarity - components with related functionality:

  • function create_node_with_relationship 98.0% similar

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

    From: /tf/active/vicechatdev/CDocs/db/db_operations.py
  • function create_node_and_ensure_relationships 88.8% 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_v1 69.5% 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 68.8% 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 68.4% 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
← Back to Browse