-
Notifications
You must be signed in to change notification settings - Fork 16
Description
Hi cruddl team! Thank you for all of your great work on this project. I apologize in advance for the length of this issue, but want to make sure I'm providing as much context as possible.
We currently have a scenario where we're leveraging the @relation directive for a number of 1:n relationships. This has given us a lot of flexibility in our API in terms of being able to fetch for entities in both directions of that relationship. What we're seeing as our collections have grown in size, though, is slow performance when those edges are leveraged, particularly when used in filtering.
Example of current schema:
type House @rootEntity {
description: String
people: [Person] @relation(inverseOf: "house")
}
type Person @rootEntity {
name: String
house: House @relation
}We really like that this allows us to do both of the following queries:
query {
allHouses {
id
description
people {
id
name
}
}
allPeople {
id
house {
id
description
}
}
}Where this had led to slow performance for larger collections, is that querying for allPeople that are associated with a particular House.id generates the following AQL:
WITH houses
RETURN {
"allPeople": (
FOR v_person1
IN people
FILTER (FIRST((
FOR v_node1 // this nested traversal is costly
IN OUTBOUND v_person1 people_house
FILTER v_node1 != null
RETURN v_node1
))._key IN ["some_id"])
RETURN {
"id": v_person1._key,
"name": v_person1.`name`
}
)
}
The filtering in that query has been inefficient on large collections because of the graph traversal, regardless of how optimized the indices are. We know that we can solve this by leveraging @reference and bypassing the edge traversal when filtering in those scenarios. Updating the schema to:
type HouseWithRef @rootEntity {
description: String
uuid: String @key
}
type PersonWithRef @rootEntity {
name: String
houseUuid: String
house: HouseWithRef @reference(keyField: "houseUuid")
}and running a query like:
query AllPeople($filter: PersonWithRefFilter) {
allPersonWithRefs(filter: $filter) {
id
name
house {
id
description
}
}
{
"filter": {
"houseUuid_in": ["some_id", "another_id"]
}
}generates the following AQL, which is much more efficient:
RETURN {
"allPersonWithRefs": (
FOR v_personWithRef1
IN personWithRefs
FILTER (v_personWithRef1.`houseUuid` IN ["some_id","another_id"])
LET v_houseWithRef1 = (IS_NULL(v_personWithRef1.`houseUuid`) ? null : FIRST((
FOR v_house1
IN houseWithRefs
FILTER ((v_house1.`uuid` > NULL) && (v_house1.`uuid` == v_personWithRef1.`houseUuid`))
LIMIT 1
RETURN v_house1
)))
RETURN {
"id": v_personWithRef1._key,
"name": v_personWithRef1.`name`,
"house": (IS_NULL(v_houseWithRef1) ? null : {
"id": v_houseWithRef1._key,
"description": v_houseWithRef1.`description`
})
}
)
}The downside to doing this is that you lose the queryability in both directions that leveraging @relation provides (e.g. querying for people in a house). So finally my question, is there a way in cruddl to leverage @reference and generate the resolvers for resolving entities in the opposite direction of the reference - essentially a @reference-based version of @relation(inverseOf: "")? I know the modeling docs mention "In contrast to relations, it is however not possible to navigate from the referenced object to the referencing object", but I wanted to check with you all.
If there's not a way to do this in cruddl, have there been any discussions on adding support for it? This can be done in pure AQL and would really help improve the performance when using cruddl for things that are a 1:n relationship. From the Arango docs:
ArangoDB does not require you to store your data in graph structures with edges and vertices, you can also decide to embed attributes such as which groups a user is part of, or _ids of documents in another document instead of connecting the documents with edges. It can be a meaningful performance optimization for 1:n relationships, if your data is not focused on relations and you don’t need graph traversal with varying depth.
Finally, is there anything else that's lost when switching a relationship from @relation to @reference aside from being able to query in both directions?
Please let me know if there's any other context I can provide, and thank you again for all of your great work on this project!