neo4j icon indicating copy to clipboard operation
neo4j copied to clipboard

Multi-depth JSON for node/edge property

Open kengz opened this issue 8 years ago • 11 comments

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?

kengz avatar Jan 22 '16 16:01 kengz

It is something we would like to do yes.

spacecowboy avatar Jan 25 '16 11:01 spacecowboy

Related to #6349

SimplicityGuy avatar Feb 05 '16 20:02 SimplicityGuy

Putting these out there as a temporary solution: flattenJSON and unflattenJSON to save and retrieve properties.

kengz avatar Feb 05 '16 22:02 kengz

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).

SimplicityGuy avatar Feb 05 '16 22:02 SimplicityGuy

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.

RashadSaleh avatar May 02 '18 15:05 RashadSaleh

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.

RashadSaleh avatar May 02 '18 16:05 RashadSaleh

This one really kills me. Two "obvious" solutions:

  1. JSON.stringify + JSON.parse.
  2. 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.

ivan-kleshnin avatar Aug 21 '18 11:08 ivan-kleshnin

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 :)

ivan-kleshnin avatar Aug 22 '18 05:08 ivan-kleshnin

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.

safizn avatar Jun 30 '19 04:06 safizn

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 :\

iMoses avatar Dec 04 '19 16:12 iMoses

Here to back support my for Nested properties in Neo4J!

royston-bowmaker avatar Jan 12 '21 06:01 royston-bowmaker