Neo4j - Filter nodes by relationship attribute lists -


lets have collections (collection) have things (thing) attached them. these collections can have sub collections contain subset of parent collection. there [:filters] relationship between parent , sub collection contain attribute lists things should filtered. attributes key same key on thing, , values key on relationship values accepted on thing. if relationship not have attributes, things should "shared" between collections.

the problem i'm having hard time solving how filter things attributes on relationship.

here graph like: graph view enter image description here

and here cypher code creating said graph:

// collections create (c1:collection {name: 'c1'})-[:filters {type: ['image']}]->(c1_img:collection {name:'c1_img'}), (c1_img)-[:filters {user: ['john']}]->(c1_user_img:collection {name:'c1_user_img'}),  (c2:collection {name: 'c2'})-[:filters {type: ['image']}]->(c2_img:collection {name:'c2_img'}), (c2_img)-[:filters]->(c1)  // c1 things create (c1i1:thing {id:1, title:"c1 thing 1", type:'image', user:'john'})-[:belongs_to]->(c1), (c1i2:thing {id:1, title:"c1 thing 2", type:'image'})-[:belongs_to]->(c1)  // c2 things create (c2i1:thing {id:1, title:"c2 thing 1", type:'image'})-[:belongs_to]->(c2), (c2i2:thing {id:1, title:"c2 thing 2", type:'image', user:'john'})-[:belongs_to]->(c2); 

lets want things should in c1_user_img. things type image , user john.

c1_img -> c1_user_img filters on user=john, c1->c1_img filters on type=image, c2_img -> c1 has no filter, c2 -> c2_img filters on type=images 

in other words, things c1i1 , c2i2 should in c1_user_img collection.

hopefully explains problem.

i've started using neo4j , still new me. have tried lot of different approaches have yet find works.

i can't create 1 list of filters , filter things that, need filter things each collection node filters might vary collections.

for instance, if try:

match (start_node:collection {name: 'c1_user_img'})<-[thing_filters:filters*]-(collections:collection)<-[:belongs_to]-(t:thing) return thing_filters:filters, t 

i work with; each thing should filtered by. , comes big problem, how match these values values of thing node. guess all() used here, since of new haven't figured out yet.

it might complex handle in cypher , parts needs done in code, nice if done query.

edit

since example gave might have been bit simple, , explanation might have been bit lacking i'm adding bit more advanced example.

lets have multiple filters in 1 filters relationship, filters should taken consideration. also, filters lists, in {user:['john', 'tom']}, values in list should accepted. in case, things user 'john' or 'tom'.

here couple of additional nodes testing:

match (c2:collection {name:'c2'}), (c1_img:collection {name:'c1_img'}) create (c2i3:thing {id:12, title:"c2 thing 3", type:'image', user:'john', extra:'foo'}), (c1_user_extra_img:collection {name:'c1_user_extra_img'}) create (c2i3)-[:belongs_to]->(c2), (c1_img)-[:filters {user: ['john'], extra: ['foo']}]->(c1_user_extra_img) return c1_user_extra_img, c2i3 

now when getting things c1_user_extra_img, require filtering on both user , extra. 1 add thing node user 'tom' , relationship filter on both 'john' , 'tom' , should return things has either user 'john' or 'tom.

thats interesting one. i've found solution - maybe else comes more elegant one:

match (start_node:collection {name: 'c1_user_img'})<-[thing_filters:filters*]-(collections:collection)<-[:belongs_to]-(t:thing) t,  reduce(acc=[], x in thing_filters | acc + keys(x)) keys, reduce(acc=[], x in thing_filters | acc + reduce(b=[], y in keys(x) | x[y]))     values all(x in range(0,size(keys)-1) t[keys[x]] = values[x]) return t 

after matching path build collection property keys , property values along relationships of path (keys, values).

using all predicate make sure elements of keys , values set properties on t.

update

if property values on relationships arrays , condition respective property value on thing needs in list small modification existing cypher statement necessary:

match (start_node:collection {name: 'c1_user_img'})<-[thing_filters:filters*]-(collections:collection)<-[:belongs_to]-(t:thing) t,     reduce(acc=[], x in thing_filters | acc + keys(x)) keys,    reduce(acc=[], x in thing_filters | acc + reduce(b=[], y in keys(x) | [x[y]])) values all(x in range(0,size(keys)-1) t[keys[x]] in (values[x]) ) return t 

by introduction square brackets in reduce values build array of arrays gets evaluated in where's predicate.


Comments

Popular posts from this blog

sequelize.js - Sequelize group by with association includes id -

android - Robolectric "INTERNET permission is required" -

java - Android raising EPERM (Operation not permitted) when attempting to send UDP packet after network connection -