neo4j
neo4j copied to clipboard
Multi-depth JSON for node/edge property
As of now a property for a node/edge must be a flat JSON, i.e. first layer's value cannot be another JSON. This makes Neo4J pretty restrictive as a database to use. Serializing or flattening a deep JSON isn't ideal either.
Are there plans to allow for using generic JSON as a property?
It is something we would like to do yes.
Related to #6349
Putting these out there as a temporary solution: flattenJSON
and unflattenJSON
to save and retrieve properties.
Personally, I'd prefer to use the json.dumps()
and json.loads()
functionality built-in the Python json modules already. A lot easier.
However, I do feel this feature needs to be added to neo4j proper without having to resort to serializing a dictionary value to a string (and vice versa).
I’ve spent the last few days just trying to wrap my head around this limitation and considering my options and I still don’t think any of the propositions out there really solve the problem (hackish solutions are a maintenance nightmare even if they work).
It’s really sad because I like neo4j a lot and it might end up indispensable for my type of project.
So my question is: Is there a particular problem that needs to be solved first so this can become a reality? Can we help you with this problem? I for one am willing to pursue this till the end until I solve it, if I can, but some direction would be very useful.
This might be a dumb idea but maybe an inexpensive solution to implement would be to use a special relationship like a “HAS” relationship that is automatically created for queries that try to write nested properties, so that something like this:
CREATE (rashad:User { profile { name { first: “Rashad”, last: “Saleh” } } })
gets translated into something like this:
CREATE (rashad:User)-[:HAS {name: “profile”}]->(profile)-[:HAS {name: “name”}]->(name {first: “Rashad”, last: “Saleh”})
And then when matching:
MATCH (rashad:User { profile { name { first: “Rashad” } } })
RETURN rashad
the query gets translated to:
MATCH (rashad:User)-[:HAS {name: “profile”}]->(profile)-[:HAS {name: “name”}]->(name { first: “Rashad” })
RETURN rashad
The user doesn’t need to know about the HAS relationship and the translations utilizing it, and since that’s the case, it probably should have a special name that won’t cause restrictions for users trying to define their own “HAS”.
This way, the database model need not change. However, the difficult part perhaps is to make sure that all cases where cypher can expect nested properties get covered with appropriate translations.
This one really kills me. Two "obvious" solutions:
-
JSON.stringify
+JSON.parse
. - Convert objects to nodes
don't even pretend to scale.
For example, we have a REST API which could be the same for all objects, say documents, containing different sets of nested objects:
Expectation
let records = await req.db.session.run(`
MATCH (parent:Document))
let documents = ... records
res.send(documents) // doesn't really matter that some documents has +stats, -breadcrumbs
// and some has +breadcrumbs, -stats
Reality 1
With approach 1) you have to handle documents on different endpoints. Or support a growing bunch of if-else
statements unnecessary coupling things together.
let records = await req.db.session.run(`
MATCH (parent:Document))
let documents = ... records
...
if (document.stats)
document.stats = JSON.parse(document.stats)
if (document.breadcrumbs)
document.breadcrumbs = JSON.parse(document.breadcrumbs)
...
res.send(documents)
And here I even omitted possible JSON.parse
errors for simplicity...
Reality 2
With approach 2) you have to use different queries and many handling branches – even more complex than previous.
let records = await req.db.session.run(`
MATCH (parent:Document))
${condX ? MATCH (parent)-[:HAS-X]->(child:Document) ""}
${condY ? MATCH (parent)-[:HAS-Y]->(child:Document) ""}
let documents = ... records
...
res.send(documents)
So, unfortunately, this issue really undermines the modelling experience. The expectation of "each nested object is really a node in disguise" is too strict and rigid. There are plenty of cases where nested objects and arrays look like the best option so it's a shame they aren't supported.
Btw, guys, to not make an impression we can only ASK for things – I would be the first to donate my 100$ to speedup this feature shall you decide to go this route :)
I was very disappointed to find that the graph does not support nested properties (nested objects). Will this be worked on any time soon. Without this feature, an unnecessary complexity is added in modeling data that isn't part of the graph, yet needed in queries matching. Take a look at RethinkDB as an example:
- https://www.rethinkdb.com/docs/nested-fields/javascript/
- https://www.rethinkdb.com/docs/data-types/
Same thing for inserting an array of objects as a node's property.
I would really like to see Neo4j become a Document Graph Database, rather than a Property Graph Database.
😥 RethinkDB I miss you.
Almost 4 years since this issue was opened and other than @spacecowboy hint that this is something you'd like to consider - just a big nothing and silence... NoSQL databases are becoming better and with better scalability, yet it seems that with Neo4J time has stopped by and none of this matter.. Such a shame :\
Here to back support my for Nested properties in Neo4J!