neo4j 查询列表中至少有一项的数组字段
neo4j query an array field that has at least one item in the list
我要查询有列表的列表
p = ['Author-1', Author-2, Author-2]
a = ['Author-1', Author-2]
b = ['Author-1', Author-2, Author-3, Author-4]
c = ['Author-4', Author-5, Author-6, Author-7]
d = ['Author-5', Author-6, Author-7, Author-8]
使用 p,如果其中一个列表至少有 author1 或 author2 return 它。
WITH p, a, b, c
UNWIND p
WITH DISTINCT p
MATCH (p)
with b as book, collect(g) as genre
WHERE genre in b.genre
return book.isbn, genre
我的真实例子 returns 没什么,类型就像上面例子中的 p 而 b.genre 就像 b,c,d,e
WHERE genre in b.genre
无法正常工作
MATCH (c:Customer { name : "Andrei Balanuta" })-[:CLIENT]-(o:Order)-[ol:ORDERLINE]-(b:Book)
UNWIND b.genre as g
WITH DISTINCT g
MATCH (b:Book)
with b as book, collect(g) as genre
WHERE genre in b.genre
return book.isbn, genre
我看到有几种方法可以做到这一点。我认为最简单的方法是搜索列表中的每个流派,然后汇总结果。
MATCH (c:Customer { name : "Andrei Balanuta" })-[:CLIENT]-(o:Order)-[ol:ORDERLINE]-(b:Book)
UNWIND b.genre as g
WITH DISTINCT g
MATCH (b:Book)
WHERE g in b.genre
RETURN book.isbn, collect(g) AS genre
如果你安装了APOC库,你也可以使用apoc.coll.intersection函数。这样的东西可能会满足您的需求。
MATCH (c:Customer { name : "Andrei Balanuta" })-[:CLIENT]-(o:Order)-[ol:ORDERLINE]-(b:Book)
UNWIND b.genre as g
WITH collect(distinct g) as customerGenres
MATCH (b2:Book)
WHERE size(apoc.coll.intersection(customerGenres, b2.genre)) > 0
RETURN b2.isbn, b2.genre, customerGenres
以上两个查询都将包含客户已购买的图书。如果你想避免这种情况,你可以这样做。
MATCH (c:Customer { name : "Andrei Balanuta" })-[:CLIENT]-(o:Order)-[ol:ORDERLINE]-(b:Book)
WITH COLLECT (b) as customerBooks
WITH customerBooks,
apoc.coll.toSet([book in customerBooks | book.genre]) as customerGenres
MATCH (b2:Book)
WHERE size(apoc.coll.intersection(customerGenres, b2.genre)) > 0
AND NOT b2 in customerBooks
RETURN b2.isbn, b2.genre, customerGenres
作为最后的想法,所有这些查询都必须搜索数据库中的每一本书以检查流派属性。如果查询性能开始下降,您可以考虑将流派变成节点而不是 属性.
在您的实际示例中,如果您在 :Book(genre) 上有索引,我们可以将其作为索引查找。
此外,我们不需要使用以后永远不会重用的变量。
MATCH (:Customer { name : "Andrei Balanuta" })-[:CLIENT]-(:Order)-[:ORDERLINE]-(b:Book)
WITH collect(DISTINCT b.genre) as genres
MATCH (b:Book)
WHERE b.genre IN genres
WITH DISTINCT b as book
RETURN book.isbn, book.genre
也就是说,让所有类型的所有书籍都与之前订购的书籍相匹配似乎有点矫枉过正,也许 LIMIT 或额外的过滤是个好主意。
对于更一般的示例,您可以使用 any() 列表谓词
https://neo4j.com/docs/cypher-manual/current/functions/predicate/#functions-any
WITH ['Author-1', 'Author-2', 'Author-2'] as p,
['Author-1', 'Author-2'] as a,
['Author-1', 'Author-2', 'Author-3', 'Author-4'] as b,
['Author-4', 'Author-5', 'Author-6', 'Author-7'] as c,
['Author-5', 'Author-6', 'Author-7', 'Author-8'] as d,
['Author-1', 'Author-2'] as desired
UNWIND [p, a, b, c, d] as list
WITH desired, list
WHERE any(item IN desired WHERE item IN list)
RETURN list
我要查询有列表的列表
p = ['Author-1', Author-2, Author-2]
a = ['Author-1', Author-2]
b = ['Author-1', Author-2, Author-3, Author-4]
c = ['Author-4', Author-5, Author-6, Author-7]
d = ['Author-5', Author-6, Author-7, Author-8]
使用 p,如果其中一个列表至少有 author1 或 author2 return 它。
WITH p, a, b, c
UNWIND p
WITH DISTINCT p
MATCH (p)
with b as book, collect(g) as genre
WHERE genre in b.genre
return book.isbn, genre
我的真实例子 returns 没什么,类型就像上面例子中的 p 而 b.genre 就像 b,c,d,e
WHERE genre in b.genre
无法正常工作
MATCH (c:Customer { name : "Andrei Balanuta" })-[:CLIENT]-(o:Order)-[ol:ORDERLINE]-(b:Book)
UNWIND b.genre as g
WITH DISTINCT g
MATCH (b:Book)
with b as book, collect(g) as genre
WHERE genre in b.genre
return book.isbn, genre
我看到有几种方法可以做到这一点。我认为最简单的方法是搜索列表中的每个流派,然后汇总结果。
MATCH (c:Customer { name : "Andrei Balanuta" })-[:CLIENT]-(o:Order)-[ol:ORDERLINE]-(b:Book)
UNWIND b.genre as g
WITH DISTINCT g
MATCH (b:Book)
WHERE g in b.genre
RETURN book.isbn, collect(g) AS genre
如果你安装了APOC库,你也可以使用apoc.coll.intersection函数。这样的东西可能会满足您的需求。
MATCH (c:Customer { name : "Andrei Balanuta" })-[:CLIENT]-(o:Order)-[ol:ORDERLINE]-(b:Book)
UNWIND b.genre as g
WITH collect(distinct g) as customerGenres
MATCH (b2:Book)
WHERE size(apoc.coll.intersection(customerGenres, b2.genre)) > 0
RETURN b2.isbn, b2.genre, customerGenres
以上两个查询都将包含客户已购买的图书。如果你想避免这种情况,你可以这样做。
MATCH (c:Customer { name : "Andrei Balanuta" })-[:CLIENT]-(o:Order)-[ol:ORDERLINE]-(b:Book)
WITH COLLECT (b) as customerBooks
WITH customerBooks,
apoc.coll.toSet([book in customerBooks | book.genre]) as customerGenres
MATCH (b2:Book)
WHERE size(apoc.coll.intersection(customerGenres, b2.genre)) > 0
AND NOT b2 in customerBooks
RETURN b2.isbn, b2.genre, customerGenres
作为最后的想法,所有这些查询都必须搜索数据库中的每一本书以检查流派属性。如果查询性能开始下降,您可以考虑将流派变成节点而不是 属性.
在您的实际示例中,如果您在 :Book(genre) 上有索引,我们可以将其作为索引查找。
此外,我们不需要使用以后永远不会重用的变量。
MATCH (:Customer { name : "Andrei Balanuta" })-[:CLIENT]-(:Order)-[:ORDERLINE]-(b:Book)
WITH collect(DISTINCT b.genre) as genres
MATCH (b:Book)
WHERE b.genre IN genres
WITH DISTINCT b as book
RETURN book.isbn, book.genre
也就是说,让所有类型的所有书籍都与之前订购的书籍相匹配似乎有点矫枉过正,也许 LIMIT 或额外的过滤是个好主意。
对于更一般的示例,您可以使用 any() 列表谓词
https://neo4j.com/docs/cypher-manual/current/functions/predicate/#functions-any
WITH ['Author-1', 'Author-2', 'Author-2'] as p,
['Author-1', 'Author-2'] as a,
['Author-1', 'Author-2', 'Author-3', 'Author-4'] as b,
['Author-4', 'Author-5', 'Author-6', 'Author-7'] as c,
['Author-5', 'Author-6', 'Author-7', 'Author-8'] as d,
['Author-1', 'Author-2'] as desired
UNWIND [p, a, b, c, d] as list
WITH desired, list
WHERE any(item IN desired WHERE item IN list)
RETURN list