Оператор Cypher с различными условиями совпадения возвращает тот же результат - PullRequest
1 голос
/ 05 февраля 2020

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

У меня есть объект голосования, который имеет поля:

  • type:String со значениями UP или DOWN.
  • argId:String, который представляет собой строковое значение идентификатора, связанное с уникальным аргументом объекта

Я пытаюсь запросить количество голосов, назначенных для заданный argId с использованием следующих запросов:

MATCH (v:Vote) WHERE v.argId = '214' AND v.type='DOWN'
RETURN {downvotes: COUNT(v)} AS votes
UNION
MATCH (v:Vote) WHERE v.argId = '214' AND v.type='UP'
RETURN {upvotes: COUNT(v)} AS votes

Обратите внимание, что вышеупомянутый шифр - работает и возвращает ожидаемый результат примерно так:

[
 {
   "downvotes": 1
 },
 {
   "upvotes": 10
 }
]

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

MATCH (v:Vote) WHERE v.argId = '214' AND v.type='UP'
MATCH (b:Vote) WHERE b.argId = '214' AND b.type='DOWN'
RETURN {upvotes: COUNT(v), downvotes: COUNT(b)}

Просто прочитав это, я думаю, что это имеет смысл, b и v объявлены как отдельные переменные, поэтому все должно быть хорошо (так я думал) .

Но его запуск дал мне это:

{
  "upvotes": 10,
  "downvotes": 10
}

Но это должно быть то, что я имею выше.

Почему это?

Я ' Я новичок в neo4j и cypher, так что я, вероятно, не понял, как полностью работает cypher.

Может ли кто-нибудь светить?

Спасибо!

ps Я использую Neo4j 3.5.6 и запускаю запросы через приложение для браузера для настольных ПК.

1 Ответ

0 голосов
/ 05 февраля 2020

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

MATCH (v:Vote) WHERE v.argId = '214' AND v.type='UP'
MATCH (b:Vote) WHERE b.argId = '214' AND b.type='DOWN'
RETURN v.type, b.type

Чтобы получить требуемый результат, вам необходимо отфильтровать значения и подсчитать их по отдельности.

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

Что-то подобное может вас устроить.

MATCH (v:Vote {argId: '214'}) 
WHERE v.type IN ['UP', 'DOWN']
RETURN { 
          upvotes: count(CASE WHEN v.type = 'DOWN' THEN 1 END), 
          downvotes: count(CASE WHEN v.type = 'UP' THEN 1 END) 
       } AS vote_result

Используя APO C, вы могли бы что-то сделать например, при этом вы сами используете значения типов для агрегирования счетчиков, а затем используете APO C для преобразования его в карту с типами в качестве ключей на карте.

MATCH (v:Vote {argId: '214'}) 
WHERE v.type IN ['UP', 'DOWN']
WITH [v.type, count(*)] AS vote_pair
RETURN apoc.map.fromPairs(collect(vote_pair)) AS votes
...