Как объединить, а затем отсортировать два списка в Cypher? - PullRequest
0 голосов
/ 06 мая 2020

Я хочу напечатать книги двух авторов в порядке выпуска.

Желаемый результат:

[
  {
     name: 'Player Piano',
     published: 1952,
     author: 'Kurt Vonnegut'
  },
  {
     name: 'Lolita',
     published: 1955,
     author: 'Vladimir Nobokov'
  },
  {
     name: 'Cat's Cradle',
     published: 1963,
     author: 'Kurt Vonnegut'
  }
]

Мой запрос выглядит так:

MATCH(kbook:Book)<-[:WROTE]-(author:Author { name: 'Kurt Vonnegut' })

MATCH(nbook:Book)<-[:WROTE]-(author:Author { name: 'Vladimir Nobokov' })
WITH kbook, nbook

ORDER BY kbook.published, nbook.published
RETURN collect(kbook) + collect(nbook)

Моя проблема : если количество книг Нобокова меньше, чем книг Курта, книги Нобокова будут повторяться до тех пор, пока их количество не станет равным (и наоборот)

Ответы [ 2 ]

2 голосов
/ 06 мая 2020

[ОБНОВЛЕНО]

Вот простой и эффективный запрос (для которого нужен только один MATCH). Например, если список имен авторов передается в параметре authNames , :

MATCH (b)<-[:WROTE]-(a:Author)
WHERE a.name IN $authNames
WITH {name: b.title, published: b.published, authors: COLLECT(a.name)} AS item
ORDER BY b.published
RETURN COLLECT(item) AS books

COLLECT(a.name) используется для преобразования значения authors в список, поскольку у книги, как правило, может быть несколько авторов.

Вы также можете создать индекс по Author(name) для оптимизации запроса.

Дополнение

Если если вы хотите получить отсортированный по дате список данных книги (с возможно разными свойствами, из разных частей БД), вы можете использовать новую поддержку обработки после объединения . Например, если вы хотите получить отсортированный список книг, написанных автором в $authNames или рецензированных рецензентом в $revNames:

CALL {
  MATCH (b)<-[:WROTE]-(a:Author)
  WHERE a.name IN $authNames
  RETURN {name: b.title, published: b.published, authors: COLLECT(a.name)} AS item
  UNION ALL
  MATCH (b)<-[:REVIEWED]-(r:Reviewer)
  WHERE r.name IN $revNames
  RETURN {name: b.title, published: b.published, reviewers: COLLECT(r.name)} AS item
}
WITH item.name AS name, apoc.map.mergeList(COLLECT(item)) AS merged
ORDER BY merged.published
RETURN COLLECT(merged) AS books

UNION ALL - это используется (вместо UNION), чтобы избежать усилий по удалению дубликатов, потому что в этом примере два подзапроса не должны создавать повторяющиеся элементы. Для дополнительных подзапросов можно добавить еще UNION s.

Используется функция apo c .map.mergeList (вместе с функцией агрегирования COLLECT), чтобы объединить данные об авторе и рецензенте одной и той же книги в единую карту.

1 голос
/ 06 мая 2020

Вы можете собрать 1-е, собрать 2-е, агрегировать список, раскрутить, вернуть и отсортировать. Попробуйте это, измененное из этой статьи: https://neo4j.com/blog/cypher-union-query-using-collect-clause/

MATCH (kbook:Book)<-[:WROTE]-(kauthor:Author {name: 'Kurt Vonnegut'})
WITH collect({name: kbook.name, published: kbook.published, author: kauthor.name}) as rows
MATCH(nbook:Book)<-[:WROTE]-(nauthor:Author {name: 'Vladimir Nobokov'})
WITH rows + collect({name: nbook.name, published: nbook.published, author: nauthor.name}) as allRows
UNWIND allRows as row
RETURN row
ORDER BY row.published
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...