假设我有集合(Collection
),它们附有东西(Thing
)。这些集合可以包含子集合,其中包含父集合的子集。父集合和子集合之间存在[:FILTERS]
关系,其中包含应过滤Thing
的属性列表。属性键与Thing
上的键相同,关系上键的值是Thing
上接受的所有值。如果关系没有任何属性,则所有Thing
应该在集合之间“共享”。
我很难解决的问题是如何通过关系中的属性来过滤事物。
以下是图表的外观: Graph view
以下是创建所述图表的Cypher代码:
// 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);
让我们说我想得到Thing
中的C1_user_img
。这将是类型Thing
和用户image
的所有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
换句话说,Thing
的C1I1和C2I2应该在C1_user_img集合中。
希望这能解释我的问题。
我刚刚开始使用Neo4j,对我来说一切都还不错。我已经尝试了很多不同的方法,但还没有找到有效的方法。
我不能只创建一个过滤器列表并按此过滤所有内容,但我需要为每个集合节点过滤内容,因为过滤器可能因集合而异。
例如,如果我尝试:
MATCH (start_node:Collection {name: 'C1_user_img'})<-[thing_filters:FILTERS*]-(collections:Collection)<-[:BELONGS_TO]-(t:Thing)
RETURN thing_filters:FILTERS, t
我找回了一些我可能会合作的东西;每个Thing
应该过滤的内容。然后是一个大问题,如何将这些值与Thing
节点的值相匹配。我想这里可以使用像all()这样的东西,但由于所有这些都是相当新的,我还没想到它。
可能在Cypher中处理这个问题太复杂了,某些部分需要在代码中完成,但如果只用查询就可以完成它。
修改
由于我给出的示例可能有点过于简单,而且我的解释可能有点缺乏,我正在添加一些更高级的示例。
假设您有一个FILTERS
关系中的多个过滤器,则应考虑所有过滤器。此外,由于过滤器是列表,如{user:['john', 'tom']}
中所示,因此应接受列表中的所有值。在这种情况下,Thing
s与用户'john'或'tom'。
以下是一些用于测试的其他节点:
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
现在获取Thing
的所有C1_user_extra_img
时,需要同时对user
和extra
进行过滤。还可以添加一个Thing
节点和用户'tom',然后在'john'和'tom'上添加关系过滤器,这应该返回所有具有用户'john'或'tom。的东西。
答案 0 :(得分:0)
这是一个有趣的。我找到了一个解决方案 - 也许其他人想出一个更优雅的解决方案:
MATCH (start_node:Collection {name: 'C1_user_img'})<-[thing_filters:FILTERS*]-(collections:Collection)<-[:BELONGS_TO]-(t:Thing)
WITH t,
reduce(acc=[], x in thing_filters | acc + keys(x)) AS keys,
reduce(acc=[], x in thing_filters | acc + reduce(b=[], y in keys(x) | x[y])) AS values
WHERE all(x in range(0,size(keys)-1) WHERE t[keys[x]] = values[x])
RETURN t
在匹配路径之后,我们为该路径的关系(keys
,values
)构建所有属性键和属性值的集合。
使用all
谓词,我们确保keys
和values
的所有元素都设置为t
上的属性。
如果关系上的属性值是数组,并且条件是事物上的相应属性值需要在该列表中,则需要对现有cypher语句进行小的修改:
MATCH (start_node:Collection {name: 'C1_user_img'})<-[thing_filters:FILTERS*]-(collections:Collection)<-[:BELONGS_TO]-(t:Thing)
WITH t,
reduce(acc=[], x in thing_filters | acc + keys(x)) AS keys,
reduce(acc=[], x in thing_filters | acc + reduce(b=[], y in keys(x) | [x[y]])) AS values
WHERE all(x in range(0,size(keys)-1) WHERE t[keys[x]] in (values[x]) )
RETURN t
通过在reduce
中为values
引入方括号,我们构建了一个数组数组,这些数组将在WHERE
的所有谓词中进行评估。