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 thing
s should filtered. attributes key same key on thing
, , values key on relationship values accepted on thing
. if relationship not have attributes, thing
s should "shared" between collections.
the problem i'm having hard time solving how filter things attributes on relationship.
here graph like: graph view
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 thing
s should in c1_user_img
. thing
s 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, thing
s 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, thing
s 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 thing
s 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
Post a Comment