Neo4j - Cypher - система галереи изображений с родителями и ребенком - PullRequest
0 голосов
/ 03 октября 2018

Я новичок в Neo4j с фоном mysql, я пытаюсь преобразовать старую систему галереи изображений mysql в графическую базу данных Neo4j, схема, с которой я приехал, представлена ​​на графике ниже:

neo4j graph

_ Есть пользовательские узлы с типами отношения буксировки:

  • Опубликовано: (:User)-[:POSTED]->(:Post)
  • Имеет аватар: (:User)-[:HAS_AVATAR]->(:Image)

_ Опубликовать узлы с типами отношений буксировки:

  • Имеет дочерний элемент для родительского сообщения галереи: (:Post)-[:HAS_CHILD]->(:Post)
  • Имеет изображение для галереидочерние сообщения: (:Post)-[:HAS_IMAGE]->(:Image)

_ конечные узлы изображения.

Это упрощенная версия, фактически каждый пост (родитель и ребенок) может иметь ссылку или видео вместоизображение и может быть прокомментировано или понравилось пользователям.

Чтобы получить все данные, которые мне нужны из графика, я использую этот шифровый запрос:

MATCH (p:Post)<-[:POSTED]-(u:User) WHERE NOT (p)<-[:HAS_CHILD]-(:Post)
MATCH (u)-[:HAS_AVATAR]->(ua:Image)
OPTIONAL MATCH (p)-[:HAS_CHILD]->(c:Post)
OPTIONAL MATCH (p)-[:HAS_IMAGE]-(i:Image)
OPTIONAL MATCH (c)-[:HAS_IMAGE]-(ci:Image)
RETURN
[p._id, [u.username, ua._id], i._id, c._id, ci._id] as post

В итоге получаетсярезультат, подобный этому:

enter image description here

Опять же, я держу этот запрос простым, для ясности,у каждого изображения есть идентификатор, ширина и высота, у каждого дочернего поста может быть свой пользователь, отличный от своего родителя, и у каждого поста есть свои комментарии и лайки от разных пользователей, реальный результат намного больше, чем этот.

Прямо сейчас мне приходится иметь дело со многими lodash/union, чтобы избавиться от всех повторяющихся результатов (идентификаторы сообщений, имена пользователей ...)

У меня вопрос, правильно ли я делаю?Есть ли лучший подход?Я на самом деле читаю о MERGE и плохо пытаюсь его реализовать.

Так что я обращаюсь к вам, ребята, и к вашим экспертам за любыми советами, особенно если он может получить все функции объединения внутри шифразапрос.

Спасибо.

1 Ответ

0 голосов
/ 03 октября 2018

Судя по комментариям, вы хотите использовать агрегацию для сбора результатов и сведения к минимуму количества строк и повторения элементов в результатах.

По вашему запросу это выглядит так, как будто выпытаясь сделать это уже путем вывода списков.Имейте в виду, что есть разница между помещением некоторых ваших результатов в списки (которые просто изменяют структуру результатов в строке) по сравнению с использованием collect() или другими подходами, которые выполняют агрегирование, так как это берет результаты из нескольких строк и собирает их вместев одну строку (для каждого ключа группировки), так что в итоге вы получите меньше строк.

Вот ваш запрос с изменениями для сбора дочерних сообщений для родительского сообщения:

MATCH (p:Post)<-[:POSTED]-(u:User) 
WHERE NOT (p)<-[:HAS_CHILD]-() 
// the above uses the degree of those relationships on the node, more efficient
OPTIONAL MATCH (p)-[:HAS_CHILD]->(c:Post) // potentially multiple children
OPTIONAL MATCH (c)-[:HAS_IMAGE]-(ci:Image) // assume at most 1 image per child post
WITH p, u, collect(c {._id, image:ci._id}) as children
OPTIONAL MATCH (p)-[:HAS_IMAGE]-(i:Image) // assume at most 1 image per post
WITH p, u, children, i
MATCH (u)-[:HAS_AVATAR]->(ua:Image) // assume at most 1 avatar per user
RETURN p {._id, image:i._id, children} as post, u {.username, avatar:ua._id} as user

Используется проекция карты для проецирования свойств с карты (или, в данном случае, свойств из узла) и добавления наших собственных свойств к карте из других сопоставленных элементов.

Альтернативно, если выхотел сделать что-то похожее, но, кроме того, собирая сообщения для каждого пользователя, вы можете сделать что-то вроде этого:

MATCH (p:Post)<-[:POSTED]-(u:User) 
WHERE NOT (p)<-[:HAS_CHILD]-() 
// the above uses the degree of those relationships on the node, more efficient
OPTIONAL MATCH (p)-[:HAS_CHILD]->(c:Post) // potentially multiple children
OPTIONAL MATCH (c)-[:HAS_IMAGE]-(ci:Image) // assume at most 1 image per child post
WITH u, p, collect(c {._id, image:ci._id}) as children
OPTIONAL MATCH (p)-[:HAS_IMAGE]-(i:Image) // assume at most 1 image per post
WITH u, collect(p {._id, image:i._id, children}) as posts
MATCH (u)-[:HAS_AVATAR]->(ua:Image) // assume at most 1 avatar per user
RETURN u {.username, avatar:ua._id} as user, posts
...