How to Use JSONProperty for Storing Nested JSON Data in neomodel
JSONProperty is a neomodel property type that serializes Python data structures to JSON strings when saving and deserializes them back when loading, enabling storage of nested dictionaries and lists in Neo4j scalar properties.
Storing complex nested data in Neo4j requires serialization since the database only supports scalar property values. The JSONProperty class in the neo4j-contrib/neomodel repository provides a seamless way to persist arbitrary Python objects—including dictionaries containing lists of dictionaries—as JSON strings while maintaining a native Python interface.
Understanding JSONProperty Implementation
In neomodel/properties.py (lines 666-684), the JSONProperty class inherits from the base Property class and participates in neomodel's inflate/deflate pipeline. This integration allows automatic conversion between Python objects and JSON strings without manual intervention during node operations.
The Deflate Method (Serialization)
When saving a node, the deflate method executes json.dumps() on your Python object, converting dictionaries, lists, numbers, and booleans into a string format that Neo4j can store. According to the source code, you can configure the ensure_ascii parameter to preserve Unicode characters rather than escaping them.
The Inflate Method (Deserialization)
Upon retrieval, the inflate method runs json.loads() on the stored string, reconstructing the original Python data structures. This process occurs transparently in neomodel/sync_/property_manager.py during database read operations, ensuring you work with native Python types rather than raw JSON strings.
Defining Models with JSONProperty
To store nested JSON data, define a StructuredNode subclass and assign JSONProperty to any attribute requiring complex data structures. The property accepts an optional ensure_ascii argument to control Unicode handling.
from neomodel import StructuredNode, StringProperty, JSONProperty
class Person(StructuredNode):
name = StringProperty(required=True)
# Store any nested JSON-compatible data
profile = JSONProperty(ensure_ascii=False) # Preserve Unicode characters
Creating and Retrieving Nested Data
When you assign nested dictionaries or lists to a JSONProperty attribute and call save(), neomodel automatically serializes the data through the deflate pipeline implemented in neomodel/sync_/node.py. Upon retrieval via Person.nodes.get(), the inflate process reconstructs the Python objects.
# Create a node with deeply nested structure
jane = Person(name="Jane Doe").save()
jane.profile = {
"age": 34,
"address": {
"street": "123 Main St",
"city": "München",
"coordinates": {"lat": 48.1351, "lon": 11.5820}
},
"preferences": ["coffee", "cycling", {"sport": "skiing", "level": "intermediate"}]
}
jane.save() # Serializes to JSON string via deflate()
# Retrieve - JSON automatically inflated to Python dict
same_jane = Person.nodes.get(name="Jane Doe")
print(same_jane.profile["address"]["city"]) # Output: München
Updating Partial JSON Structures
Since JSONProperty returns mutable Python objects, you can modify nested values and save the node. However, you must reassign the property to trigger the deflate cycle in neomodel/sync_/property_manager.py.
profile = same_jane.profile
profile["preferences"].append("reading")
same_jane.profile = profile # Required to trigger serialization
same_jane.save()
Querying JSONProperty Content
Neo4j stores JSONProperty values as strings, limiting query capabilities to string operations. You cannot query specific nested keys directly; instead, use string containment filters to match substrings within the JSON representation.
# Find profiles containing the word "cycling" (string match)
cycling_people = Person.nodes.filter(profile__contains='"cycling"')
Summary
JSONPropertyinneomodel/properties.pyserializes Python objects to JSON strings usingjson.dumps()during the deflate phase.- The
inflatemethod in the same file deserializes stored strings back to Python objects usingjson.loads(). - Set
ensure_ascii=Falseto preserve Unicode characters in your JSON data. - Since Neo4j stores these as scalar strings, querying is limited to string matching operations rather than structured JSON queries.
- Always reassign the property value after mutation to ensure neomodel detects changes and triggers serialization.
Frequently Asked Questions
What is the difference between JSONProperty and ArrayProperty in neomodel?
ArrayProperty stores homogeneous lists of primitive Neo4j types (strings, integers, booleans) as native Neo4j arrays, allowing indexed access and type-specific queries. JSONProperty stores heterogeneous nested structures as serialized JSON strings, supporting dictionaries containing mixed types and nested objects, but with limited queryability since Neo4j treats the value as a single string.
Can I use JSONProperty with the async API in neomodel?
Yes, JSONProperty works with both synchronous and asynchronous neomodel APIs. While the examples shown use the synchronous implementation in neomodel/sync_/node.py, the property class itself is agnostic to the sync/async boundary. The inflate/deflate logic executes during property management regardless of which API layer handles the database connection.
How do I handle Unicode characters when using JSONProperty?
Pass ensure_ascii=False when defining the property: profile = JSONProperty(ensure_ascii=False). This parameter passes directly to Python's json.dumps() method in the deflate implementation, preventing Unicode characters from being escaped as ASCII sequences and preserving human-readable international text in your Neo4j database.
Is it possible to index or query specific keys inside a JSONProperty?
No. Because JSONProperty stores data as serialized strings in Neo4j, the database cannot index individual nested keys or values. You can only perform string containment queries using filters like profile__contains. For queryable nested structures, consider modeling the data as separate nodes and relationships rather than using JSONProperty.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →