Как проверить, находится ли элемент в коллекции узлов, используя Cypher?

Я начинаю с Neo4j/Cypher, у меня есть несколько узлов, содержащих свойство, которое представляет собой массив целых чисел. Я хочу проверить, находится ли данный номер в коллекции узлов, и если да, то добавить этот узел к результатам. Мой запрос выглядит так:

MATCH (a) WHERE has(a.user_ids) and (13 IN a.user_ids) RETURN a

где 13 — заданный user_id. Выдает синтаксическую ошибку:

Type mismatch: a already defined with conflicting type Node (expected Collection<Any>)

Любая идея, как я могу это сделать?

Заранее спасибо.


person ksiomelo    schedule 18.11.2013    source источник
comment
Мой ответ раздражал меня, поэтому я изучил его немного подробнее и обновил его некоторыми дополнительными мыслями, если вам интересно.   -  person jjaderberg    schedule 20.11.2013


Ответы (1)


Вы можете попробовать предикат ANY, который возвращает true, если какой-либо член коллекции соответствует какому-либо критерию.

MATCH (a) WHERE has(a.user_ids) and ANY(user_id IN a.user_ids WHERE user_id = 13)

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

Изменить:

Меня беспокоило, почему ваш запрос не работал и почему мой ответ казался обратным и косвенным, поэтому я провел простой тест. По сути, ваш исходный запрос работает, если вы поместите ссылку на свойство в круглые скобки:

MATCH (a)
WHERE has(a.user_ids) and (13 IN (a.user_ids))
RETURN a

Это легче читать, поэтому я должен был ответить. Но я все еще не мог понять, почему скобки нужны здесь, когда их нет в других случаях. Они не были необходимы внутри ANY() выше, и если вы «отсоедините» коллекцию от узла

MATCH (a)
WITH a.user_ids as user_ids, a
WHERE 13 IN user_ids
RETURN a

нет проблем. По какой-то причине Cypher необходимо указать оценить a.user_ids перед IN, иначе он проигнорирует user_ids и попытается оценить 13 IN a. IN указан как оператор в документации, но в этом отношении он работает иначе, чем другие операторы. Например

MATCH (a) RETURN 13 + a.user_ids

возвращается нормально и

MATCH (a) RETURN 13 * a.user_ids
MATCH (a) RETURN 13 < a.user_ids

терпит неудачу, но потому, что a.user_ids является коллекцией, а не потому, что a является узлом. Наверное, это не очень важно, использовать скобки достаточно просто, но было бы интересно узнать, зачем они нужны.

Я также сравнил свой ответ с вашим исходным запросом с добавленными скобками, чтобы увидеть, есть ли какие-либо недостатки в производительности по сравнению с более косвенным способом. Оказывается, план выполнения почти идентичен, 13 IN (a.user_ids) рефакторинг для использования ANY(), как в моем ответе.

Мой ответ:

Filter(pred="any(user_id in Product(a,user_ids(6),true) where user_id == Literal(13))", _rows=1, _db_hits=8)
    AllNodes(identifier="a", _rows=8, _db_hits=8)

Ваш запрос + ():

Filter(pred="any(-_-INNER-_- in Product(n,user_ids(6),true) where Literal(13) == -_-INNER-_-)", _rows=1, _db_hits=8)
    AllNodes(identifier="n", _rows=8, _db_hits=8)

Наконец, в вашем случае вам, вероятно, не нужно проверять наличие свойства с помощью has(). Отсутствующие свойства и null обрабатываются по-разному в версии 2.0, и если свойство не существует, 13 IN (a.user_ids) будет оцениваться как false, поэтому обычно нет причин проверять существование свойства перед оценкой свойства, опасаясь нарушения запроса. Место для использования has() было бы, когда существование свойства имеет значение само по себе, и это, вероятно, будет другим свойством, чем оцениваемое, то есть WHERE has(a.someProperty) AND 13 IN (a.someOtherProperty).

Поскольку разницы в производительности нет, более читабельный запрос лучше, и поскольку вам, насколько я вижу, действительно не нужно проверять наличие свойства, я думаю, что ваш запрос должен быть

MATCH (a)
WHERE 13 IN (a.user_ids)
RETURN a
person jjaderberg    schedule 18.11.2013
comment
Спасибо за такой полный и педагогический ответ. Я бы +100, если бы мог. Я надеюсь, что это поможет и другим людям. Лучший, - person ksiomelo; 20.11.2013
comment
has больше нет в Neo4j, теперь он заменен на exists - person Vladimir Salin; 27.03.2018