How to make a join in a graphql schema

Hi everyone,

Im beginning with faunadb/graphql and i just encountered a spicy situation: i can’t ‘make’ a join in my graph ql schema.

Explanations:

Based on the tutorial provided by fauna db, i have uploaded a task list schema (here)

type Task {
    title: String!
    completed: Boolean
    user: User!
}

type User {
    username: String! @unique
    tasks: [Task!] @relation
}

type Query {
    allTasks: [Task!]
    allUsers: [User!]
    userByUsername(username: String!): User!
    tasksByCompletedFlag(completed: Boolean!): [Task!]
    tasksByUser(user: User): [Task!]
}

Probleme is that i tried to add my own query taskByUser which is supposed to query all tasks by a choosen user (ideally their id), but the graphql playground keep telling me that the User type isn’t an input type

I then tried to pass it directly a user id with an hazardous query which didn’t work either.

So, here’s my question: is it possible to directly do this in a schema or do i have to create a resolver ?

Sorry for my english & many thanks in advance :pray:

Hi @Florian. Let’s see if we can cool off the spicy! :yum:

I will ultimately advise that you not use the taskByUser query, because there is an easier, more GraphQL-canonical way to do it. But I’ll try to address your question directly first.

Input types

Correct! The only types that can be used as input arguments are Scalars (e.g. String, Int, etc.) Input types are defined with the input keyword, rather than type. for example:

input LoginInput {
  username: String!,
  password: String!
}

So you cannot specify User as an input. But you can specify an ID type (which is basically just an alias for String | Int)

This not not Fauna specific. It’s part of GraphQL. Check out the docs for input types and ID on graphql.org/learn/schema

Using ID

You can try the following instead:

  tasksByUser(user: ID): [Task!]

But you will get another error.

Type mismatch: field 'user' defined at object 'Task' has type 'User'.

See, the schema we provided is just a short-hand for:

  tasksByUser(user: ID): [Task!] @index(name: "tasks_by_user")

and it’s trying to create a new index on the fly. Fauna knows that there is a user field and that it’s an object type.

Note that there is already an index created for you based on the @relation directive you provided, and it’s name is probably something like task_user_by_user. It’s used by Fauna to help expand query selections. You cannot use this directly in GraphQL because it’s indexed on the raw user type, which is a Ref, for example Ref(Collection("task"), "123456789").

If you want to query an index by an ID directly, then you need to specify the index ahead of time, and include it in the schema. Assuming you have Task and User Collections existing in your DB, you can create the Index in the dashboard

or run this in the shell:

CreateIndex({
  name: "tasks_by_user",
  unique: false,
  serialized: true,
  source: "Task",
  terms: [
    {
      field: ["data", "user", "id"]
    }
  ]
})

then you can intentionally reference it in your schema when you upload:

type Query {
  # ...
  tasksByUser(user: ID): [Task!] @index(name: "tasks_by_user")
  # ..
}

How to do this the GraphQL way without any extra work

My advise to not create any top level query for “object_by_object” unless you are trying to wrap additional logic around it. In that case, you’re looking at using @resolver to work with Functions.

GraphQL lets you query data as if it is… a graph!! So let’s “traverse” the graph to find all tasks that belong to a given user.

query TasksByUser {
  # findUserById is automatically generated for you
  findUserById(id: "123456789") { 
    _id
    tasks {
      _id
      title
      completed
    }
  }
}

Cool thing is that this is already ready for pagination!

query TasksByUser {
  findUserById(id: "123456789") { 
    _id
    # can paginate user tasks
    tasks (_size: 10) {
      _id
      title
      completed
    }
  }
}
1 Like

Thanks a lot @ptpaterson :pray:

I did indeed use findUserByID in order to obtain all tasks that belong to a user. It was way easier in this case!

Thanks again for taking the time to answer me. Have a nice day :smiley:

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.