Neo4j - 按关系属性列表过滤节点
Neo4j - Filter nodes by relationship attribute lists
假设我有 collections (Collection
) 附有东西 (Thing
)。这些 collection 可以有包含 parent collection 子集的子 collection。 parent 和包含属性列表的子 collection 之间存在 [:FILTERS]
关系,Thing
应根据该属性列表进行过滤。属性键与 Thing
上的键相同,关系上键的值是 Thing
上接受的所有值。如果关系没有任何属性,所有 Thing
s 应该 "shared" 在 collections.
之间
我很难解决的问题是如何根据关系上的属性过滤事物。
图表可能如下所示:
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);
假设我想得到应该在 C1_user_img
中的 Thing
s。那将是类型为 image
且用户为 john
的所有 Thing
。
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_imgcollection.
希望这能解释我的问题。
我刚开始使用 Neo4j,一切对我来说还是很陌生。我已经尝试了很多不同的方法来解决这个问题,但还没有找到有效的方法。
我不能只创建一个过滤器列表并以此过滤所有内容,但我需要为每个 collection 节点过滤内容,因为过滤器可能因 collections 而异。
例如,如果我尝试:
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
现在,当获取 C1_user_extra_img
的所有 Thing
时,需要对 user
和 extra
进行过滤。还可以添加一个带有用户 'tom' 的 Thing
节点,然后在 'john' 和 'tom' 上添加关系过滤器,并且应该 return 所有具有用户 'john' 或 'tom.
这很有趣。我找到了一个解决方案 - 也许其他人提出了一个更优雅的解决方案:
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
.
上的属性
更新
如果关系上的 属性 值是数组,并且条件是事物上相应的 属性 值需要在该列表中,则需要对现有的密码语句进行小的修改:
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
的所有谓词中进行评估。
假设我有 collections (Collection
) 附有东西 (Thing
)。这些 collection 可以有包含 parent collection 子集的子 collection。 parent 和包含属性列表的子 collection 之间存在 [:FILTERS]
关系,Thing
应根据该属性列表进行过滤。属性键与 Thing
上的键相同,关系上键的值是 Thing
上接受的所有值。如果关系没有任何属性,所有 Thing
s 应该 "shared" 在 collections.
我很难解决的问题是如何根据关系上的属性过滤事物。
图表可能如下所示:
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);
假设我想得到应该在 C1_user_img
中的 Thing
s。那将是类型为 image
且用户为 john
的所有 Thing
。
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_imgcollection.
希望这能解释我的问题。
我刚开始使用 Neo4j,一切对我来说还是很陌生。我已经尝试了很多不同的方法来解决这个问题,但还没有找到有效的方法。
我不能只创建一个过滤器列表并以此过滤所有内容,但我需要为每个 collection 节点过滤内容,因为过滤器可能因 collections 而异。
例如,如果我尝试:
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
现在,当获取 C1_user_extra_img
的所有 Thing
时,需要对 user
和 extra
进行过滤。还可以添加一个带有用户 'tom' 的 Thing
节点,然后在 'john' 和 'tom' 上添加关系过滤器,并且应该 return 所有具有用户 'john' 或 'tom.
这很有趣。我找到了一个解决方案 - 也许其他人提出了一个更优雅的解决方案:
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
.
更新
如果关系上的 属性 值是数组,并且条件是事物上相应的 属性 值需要在该列表中,则需要对现有的密码语句进行小的修改:
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
的所有谓词中进行评估。