I want to render people
you may know, so I want to filter friend object
and get only those who are not linked with myFriend
field, and friend Request
field.
There’s currently no good way to express such a query on the platform.
I will tag this as a feature request.
We’re considering this with an ArcQL extension to add an IN
clause. So given:
type User {
age: Int
name: String
friendRequests: [User!]
friends: [User!]
following: [User!]
}
And you want to filter the friends field to exclude those in the friendRequest
and following
fields you could write this ArcQL:
query {
find(type: User, arcql: "*"){
friends(arcql:"hypi.id NOT(hypi.id IN FIELD friendRequests.hypi.id WHERE name = 'Courtney' OR hypi.id IN FIELD following.hypi.id WHERE age > 17)"){
...
}
}
}
There would be two new syntax additions, the NOT
group and the IN <FIELD|TYPE>
expression.
-
<fieldExpr> NOT(<expr>)
- this addition would exclude any results returned by<expr>
-
<fieldExpr> IN <FIELD <fieldName>|TYPE <Typename> WHERE <expr>
- lets you filter by an arbitrary sub-query. IfFIELD
follows theIN
keyword then it filters rows in the current type. Otherwise, the filter is applied to the type given byTYPE
. TheWHERE
clause will be used to filter on the field or type.
For example :
type AppInstance {
domain: String
release: AppRelease
}
type App {
name: String
releases: [AppRelease!]
}
type AppRelease {
name: String
}
In this model, I want to find AppInstance
objects by app name. The only relationship between App
and AppInstance
is that both AppInstance
and App
has a field of type AppRelease
. With the proposed extensions we can find AppInstance
s by App
name using the following query:
query {
find(type: AppInstance, arcql: "release.hypi.id IN TYPE App.release.hypi.id WHERE name = 'app1' AND releases.hypi.id = this.hypi.id)"){
...
}
}
What do you think of this proposal deepakKashyap?
This would be similar to SQL IN operator and would it be translate to the following?
ARCQL
find(type: AppInstance, arcql: "release.hypi.id IN TYPE App.release.hypi.id WHERE name = 'app1')
SQL
Select * FROM AppInstance WHERE release.hypi.id IN App.release.hypi.id = "this.hypi.id"
Roughly yes but the actually SQL would be a little more complex.
Every .
in an ArcQL query leads to a JOIN on the type being implicitly referenced. I imagine the SQL
For the query
release.hypi.id IN TYPE App.release.hypi.id WHERE name = ‘app1’ AND releases.hypi.id = this.hypi.id)
it’ll generate will be similar to:
SELECT field1,...fieldN FROM AppInstance i
INNER JOIN AppRelease r ON i.hypi.id = r.hypi.id ...
WHERE r.hypi.id IN (
SELECT r2.hypi.id FROM App a
INNER JOIN AppRelease r2 ON r2.hypi.id = a.hypi.id AND r2.hypi.id = r.hypi.id
WHERE a.name = 'app1'
)
That’s more what I expect this ArcQL query will have to generate (the syntax isn’t 100% valid SQL, just demonstrating the main form of the query).
Okay, that makes sense!
Both syntax are now possible. The two are shown and explained a bit more below
release.hypi.id TYPE IN App:release.hypi.id WHERE name = ‘app1’ AND releases.hypi.id = this.hypi.id
hypi.id FIELD IN friendRequests.hypi.id WHERE name = ‘Courtney’ OR hypi.id FIELD IN following.hypi.id WHERE age > 17
Both are now possible queries. Given these types in your schema:
type User {
user: Account
followedBy: [User!]
friendRequest: [User!]
friends: [User!]
}
type Post {
createdBy: User
title: String!
}
Two possible queries that couldn’t be expressed before are:
- What are the posts from my friends.
createdBy.hypi.id TYPE IN User:friends.hypi.id WHERE hypi.id = ‘’
- Who are people I may know? Essentially, Who are my friends and who are their friends that are not my friends
hypi.id != ‘’ AND friends.hypi.id FIELD IN friends.hypi.id WHERE hypi.id = ’
This query says
- “find the ids of my friends” (friends.hypi.id WHERE hypi.id = '’)
- “find the ids of any user who are friends with those friends of mine” (friends.hypi.id FIELD IN)
- “Return all matching users, except my user” (hypi.id != ‘’)
What are these doing? Both forms of queries
<fieldExr> TYPE IN
and <fieldExpr> FIELD IN
are translated to SQL sub-queries with the IN
clause.
Notice, the fields that are selected are all ID fields. It MUST be a scalar field (doesn’t have to be ID but must be scalar).
Two things happen in the queries above, a JOINs friends.hypi.id
does a self-JOIN on the User
table and then <FIELD|TYPE> IN...
does a SQL IN
on the results of the query on the right hand side of the FIELD IN
.
The WHERE
clause can be arbitrarily complex supporting all possibilities in ArcQL.
To better exemplify, the what are the posts from my friends query above roughly translates to this SQL (unnecessary parts omitted):
SELECT
h0.`title` AS h0_t00,
h0.`hypi_id` AS h0_h00,
h0.`hypi_created` AS h0_h01
FROM
Post h0
INNER JOIN User h2 ON h0.`createdBy.id` = h2.`hypi.id`
WHERE
h2.`hypi.id` IN (
SELECT
h3.`hypi.id` AS h3_h21
FROM
User h1
INNER JOIN Junctions ON ...
INNER JOIN User h3 ON j0.`toId` = h3.`hypi.id`
WHERE
h1.`hypi.id` = ?
AND j0.<...>...
ORDER BY
h1.hypi_id
)
The who people you may know query is roughly:
SELECT
h0.`hypi_id` AS h0_h00,
h0.`hypi_created` AS h0_h01,
h1.`username` AS h1_u00,
h1.`hypi_id` AS h1_h00,
h1.`hypi_created` AS h1_h01
FROM
User h0
LEFT JOIN Account h1 ON h0.`user_id` = h1.`hypi.id`
WHERE
(
h0.`hypi.id` != ?
AND h0.`hypi.id` IN (
SELECT
h2.`hypi.id` AS h2_h12
FROM
User h0
INNER JOIN Junctions j0 ON h0.`hypi.id` = j0.`fromId`
INNER JOIN User h2 ON j0.`toId` = h2.`hypi.id`
WHERE
h0.`hypi.id` = ?
AND j0.<...>...
)
)