All results with 3 or more relationships of a specified type


#1

Given the schema:

define
person sub entity plays has_account, has name;
bank-account sub entity plays is_account, has name;

name sub attribute datatype string;
account sub relationship relates has_account, relates is_account;
has_account sub role;
is_account sub role;

How would I find every person with 3 or more "bank-account"s?

The closest I’ve gotten is the following query:

match
$p isa person;
$a isa bank-account;
$a2 isa bank-account;
$a3 isa bank-account;
$a != $a2;
$a2 != $a3;
(has_account: $m, is_account: $a);
(has_account: $m, is_account: $a2);
(has_account: $m, is_account: $a3);
get $p;

I know the above isn’t correct based purely on how it looks but the query still runs… it just returns incorrect results.


#2

you’d at least have to add $a != $a3. That might be enough already.


#3

@tomen, I’ve updated my query to the following:

match
$p isa person;
$a isa bank-account;
$a2 isa bank-account;
$a3 isa bank-account;
$a != $a2;
$a2 != $a3;
$a3 != $a;
(has_account: $m, is_account: $a);
(has_account: $m, is_account: $a2);
(has_account: $m, is_account: $a3);
get $p;

While I think logically that’s the more correct query (given that it was possible for $a to be equal to $a3 in my original query); I don’t think this line of reasoning is going to yield a correct result.

The test data I’m using looks like this:

insert
$p isa person has name “Bob”;
$p_a1 isa bank-account has name “Checkings”;
(has_account: $p, is_account: $p_a1) isa account;

$p2 isa person has name “John”;
$p2_a1 isa bank-account has name “Checkings”;
$p2_a2 isa bank-account has name “Savings”;
(has_account: $p2, is_account: $p2_a1) isa account;
(has_account: $p2, is_account: $p2_a2) isa account;

$p3 isa person has name “Susan”;
$p3_a1 isa bank-account has name “Checkings”;
$p3_a2 isa bank-account has name “Savings”;
$p3_a3 isa bank-account has name “Backup Checkings”;
(has_account: $p3, is_account: $p3_a1) isa account;
(has_account: $p3, is_account: $p3_a2) isa account;
(has_account: $p3, is_account: $p3_a3) isa account;

Bob has one bank account (Checkings), John has two bank accounts (Checkings, Savings), and Susan has three bank accounts (Checkings, Savings, Backup Checkings). I would expect if the above query is correct that only Susan would be returned. This isn’t the case though as all the results (Bob, John, and Susan) are returned.


#4

Hi @BFergerson

shouldn’t your query have ‘$p’ instead of ‘$m’? The person should play the role ‘has_account’, right?


#5

@marco, that did the trick. Tried to abstract the problem away from my particular domain and left the original variable names in there. That does mean that @tomen’s suggestion was correct.

Being so, is this really the best way to query entities based on the number of a particular relationship they have? If so to expand it to 4 or more I would have to write:

match
$p isa person;
$a isa bank-account;
$a2 isa bank-account;
$a3 isa bank-account;
$a4 isa bank-account;
$a != $a2;
$a2 != $a3;
$a3 != $a4;
$a3 != $a;
$a4 != $a2;
$a4 != $a;
(has_account: $p, is_account: $a);
(has_account: $p, is_account: $a2);
(has_account: $p, is_account: $a3);
(has_account: $p, is_account: $a4);
get $p;

And then going to a higher number of comparison would mean the queries get really ugly. For example, finding anyone with 10 or more "bank-account"s. What’s the best way to accomplish that?


#6

To my knowledge, that is the farest you can go with GRAQL. If you want to make the number of bank accounts variable, you might do something like this:

match (has_account:$p, is_account:$a) isa account; aggregate group $p count;

This will give you each person and the number of accounts it has. You could then do something with the response in your application.


#7

@tomen, that query returns all the “person” entities and the number of “bank-account” relationships they have. I could definitely use this result in a multi-step calculation controlled in the application layer.

Is it correct that there isn’t a way to limit, order, or filter based on the “bank-account” relationship count though? Like iterating down from most “bank-account” relationships to least?