Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eager Loading & Serialising Relationships #16

Closed
adam-cowley opened this issue Jul 22, 2018 · 3 comments
Closed

Eager Loading & Serialising Relationships #16

adam-cowley opened this issue Jul 22, 2018 · 3 comments

Comments

@adam-cowley
Copy link
Owner

Opening up a private discussion with @noumaans.

I'm planning to write an enhancement to improve the serialisation of relationships. Say we have a Movie node, and we want to also eager load the Director of the movie.

Movie: {
  name: 'string',
  directed_by: {
     type: 'relationship',
     target: 'Person',
     properties: {
        budget: 'number', // budget spent on direction
     }
  }
}

We'll get something similar to the following:

{
    "_id": 7288,
    "languages": [
        "English",
        " French",
        " Swedish"
    ],
    "year": 2009,
    "imdbId": "1022603",
    "runtime": 95,
    "imdbRating": 7.8,
    "movieId": "69757",
    "countries": [
        "USA"
    ],
    "imdbVotes": 363490,
    "title": "(500) Days of Summer",
    "tmdbId": "19913",
    "plot": "An offbeat romantic comedy about a woman who doesn't believe true love exists, and the young man who falls for her.",
    "poster": "http://ia.media-imdb.com/images/M/MV5BMTk5MjM4OTU1OV5BMl5BanBnXkFtZTcwODkzNDIzMw@@._V1_SX300.jpg",
    "released": "2009-08-07",
    "director": [{
        "_id": 31462,
        "name": "Marc Webb"
    }]
}

This approach has a couple of problems:

  1. An array of nodes is returned even if only one exists
  2. There is no visibility of the properties stored against the relationship - what was the director's salary?

Proposed Changes

  1. Introduce either a cardinality option to the configuration to return the first result as an object
  directed_by: {
     type: 'relationship',
     cardinality: 1, // or limit, 
  }

Or a new type:

  directed_by: {
     type: 'node',  // or 'nodes' to return an array of nodes
     target: 'Director',
  }
  1. Where you want to see a relationship with it's properties, keep the relationship type but use this to return the relationship and node.

Define:

  directed_by: {
     type: 'relationship',
  }

To return:

{
    "_id": 7288,
    // ...
    "directed_by": {
        "_id": 31462,
        "salary": 50000, // I don't know much much a director earns?!
        "node": { // kind of inconvenient name because, see notes...
          "_id": 31462,
          "name": "Marc Webb"
        }
    ]
}

In the example above, the properties for the relationship are flattened and then a node key for the node at the other end.

Neo4j's API's define relationships as having a startNode, endNode and other. Because the definition has an in/out direction, the only applicable name would be other - that's not ideal. If Person A knows Person B, using startNode or endNode could lead to inconsistent returns.

Potentially, this could be defaulted to other, with an option to configure the key name if required.

  directed_by: {
     type: 'relationship',
     alias: 'person'
  }
{
    "_id": 7288,
    // ...
    "directed_by": {
        "_id": 31462,
        "salary": 12000, 
        "person": { // as per alias
          "_id": 31462,
          "name": "Marc Webb"
        }
    ]
}

This could also default to the target name:

{
    "_id": 7288,
    // ...
    "directed_by": {
        "_id": 31462,
        "salary": 12000, 
        "Person": { // We've defined the target to be Person
          "_id": 31462,
          "name": "Marc Webb"
        }
    ]
}

All comments welcome...

adam-cowley added a commit that referenced this issue Sep 19, 2018
- Introduced 'node', 'nodes', 'relationship' and 'relationship' types (#16)
- Improved eager loading and
- Rewrote create and merge services
- Support more flexible target definitions (fixes #18)
- Temporal and Spatial Support (fixes #8)
- Improved test coverage
@purplemana
Copy link
Contributor

Could you explain more about the differences between relationship and node in terms of use cases and returned results? Thanks.

@adam-cowley
Copy link
Owner Author

The idea is that you can get just the node (ie Adam lives in Swindon) or information on the relationship (Adam has lived in Swindon since 2015). A relationship will return properties for the relationship and the end node:

// type: 'relationship'
{
  since: '2015-01-01', // <-- rel properties
  node: { // <-- node
    _id: 2,
    _labels: ['Location'],
    name: "Swindon"
  }
}

Whereas the node will only return the end node:

// type: 'node'
{
  _id: 2,
  _labels: ['Location'],
  name: "Swindon"
}

The same is true for nodes and relationships, except these are collections/arrays rather than a single value. I hope that clears things up.

@IrenaDJ
Copy link

IrenaDJ commented Jan 12, 2019

I recently encountered a problem with the type 'relationships' in defining schema (it works only for type relationship). I'm using typescrypt and the problem can be avoided by defining the whole schema object as type 'any' instead of Neode.SchemaObject

`import Neode from "neode";
// Neode.SchemaObject
const schema: any = {

// . . .

children: {
type: 'relationships', // <-- this line caused the problem
target: 'Person',
direction: 'out',
relationship: "CHILD_OF",
eager: true
},
};
export const personModel = (n4j: Neode) =>
n4j.model('Person',schema );
`
This should be updated in the file with types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants