activegraph icon indicating copy to clipboard operation
activegraph copied to clipboard

Think about ways to return specific fields on nodes

Open cheerfulstoic opened this issue 8 years ago • 4 comments

Would be nice to be able to say what fields that you want to return in specific cases and have ActiveNode / ActiveRel populated objects. I was returning some nodes and there was a large text field that I wasn't using in a particular request.

  • We could have it happen when building a query Model.with_properties(:prop1, :prop2).find(id)
  • We could define that properties are lazy loaded property :prop1, lazy_load: true and then specify later either on the object or as part of the thing that will make the query that we want to load that property
  • We also may want to consider always only loading the properties on the model

This would probably make the Cypher queries uglier...

cheerfulstoic avatar Nov 19 '15 06:11 cheerfulstoic

@cheerfulstoic I see this to be important from performance perspective as well, in the video by Mark Needham and Petra Selmer on 'Tuning your Cypher' over at http://graphconnect.com/, they state that rather than returning all node properties, if you pick specific properties, the queries are expected to perform better.

rahulmeena13 avatar May 18 '16 13:05 rahulmeena13

I don't think there is a way to do something "clean" considering how Cypher works but I see an "quite easy" to implement solution

MyModel.query_as(:m).return('collect({name: m.name, slug: m.slug, label: 'MyModel'}')

This way we could "fake" the label and force neo4jrb to hydrate the collection accordingly.

Grafikart avatar May 04 '18 11:05 Grafikart

Another solution (a bit more complicated) would be to match query_as and fields name :

MyModel.query_as(:m).return('ID(m), m.uuid, m.id, m.name, m.slug, COUNT(relations) as count').each_with_hydration do |row|
    row['m.slug'] # would be the slug
    row['m'] # would be "auto hydrated" into a <#MyModel>
end

This could work with the each method but it would have too many side effects in my opinion, so creating a new method seems better.

I need this feature too, so I'll try to take a look to see if it's possible to make this work.

Grafikart avatar May 04 '18 11:05 Grafikart

I have thought about the solution of having Maps like the suggestion in your first comment. My hesitance about that has been that when you return nodes / relationships from Neo4j, you don't get a map but rather a more complex object to describe said nodes / relationships. In order to support this we'd need two different paths to wrap nodes.

I've generally been able to get around this by just doing a pluck and getting the attributes that I need, though I realize that's not as nice. Though I do wonder about the potential confusion of having situations where objects have been hydrated from the database without all the properties. I could easily picture developers coming along behind and being super confused.

Another way that I've dealt with this is to define a method on Query called pluck_struct which takes in a ruby Struct and which maps it's members to fields which are being returned. It then plucks those properties and hydrates objects of the Struct. This doesn't give you validations / associations / etc..., but it does make it pretty clear that you're not dealing with a model object. It also has the advantage that you can build objects which are aggregations of multiple different nodes / relationships which are appropriate to the particular query.

cheerfulstoic avatar May 20 '18 00:05 cheerfulstoic