GraphQL query how to pass variables - graphql

Hi all I have a query where I am trying to get messages from a user with a specific uuid or a role that matches the users role. I am unsure of how to properly use the _ilike or % in this instance. I've tried a myriad of combinations yet the role messages never get returned. My query as it sits now and the hook used in the component are below.
I appreciate any feedback.
Here is my query
query getUserMessages($userId: String!) {
messageReceivers(
where: { _or: [{ userId: { _eq: $userId } }, { message: { roles: { _ilike: "%" } } }] }
) {
messageId
userId
message {
id
audioLink
body
videoLink
user {
firstName
lastName
photo
title
specialty
profession
location
}
}
}
}
Using the lazyquery hook in component
const [getUserMessages, { error, called, loading, data }] = useGetUserMessagesLazyQuery()
const userRole = `%${user.role}%`
useEffect(() => {
getUserMessages({
variables: { userId: user?.id, message: { roles: { _ilike: userRole } } },
})
}, [user])

You are incorrectly passing userRole to the query. To fix it, apply userId's pattern to userRole.
In the query definition, add $userRole in the operation signature (You are currently hardcoding _ilike to % in the query, but you want set it dynamically as $userRole).
In the calling function, send the variables correctly variables: { userId: user?.id, userRole: userRole}.
The GraphQL Variable docs neatly describe how this fits together.

Thanks #fedonev! Though I didn't see your solution you were absolutely correct. I was able to work it out a little differently and I hope this helps someone who's run into the same issue.
By creating the variable $role in the query I was able to use the same syntax as was being used by the userId variable. If anyone has this issue please feel free to comment I will happily help if I can.
Query
query getUserMessages($userId: String!, $role: String = "%") {
messages(
where: {
_or: [{ roles: { _ilike: $role } }, { messageReceivers: { userId: { _eq: $userId } } }]
}
order_by: { createdAt: desc }
) {
createdAt
id
body
audioLink
videoLink
roles
}
Call from in component
useEffect(() => {
getUserMessages({
variables: { userId: user?.id, role: user?.role },
})
}, [user])

Related

Create GraphQL connection between User and Role Type via Role and query them

I want to create a GraphQL connection between User <> Role <> Role_Type and finally get the User Role Type back with a query. Here is brake it down to the only important lines of code:
type Query {
getUsers: [User]
}
type User {
_id: ID
firstname: String
roles: [Role]
}
type Role {
_id: ID
role_type_id: ID
role_types: [Role_Type]
user_id: ID
}
type Role_Type {
_id: ID
name: String
}
and in the User resolver I have:
Query: {
getUser: async (root, { _id }) => {
return prepare(await DBUsers.findOne(ObjectId(_id)))
}
},
User: {
roles: async ({_id}) => {
return (await MongoDBRoles.find({user_id: _id}).toArray()).map(prepare)
}
}
and for the Role resolver:
Role: {
role_types: async ({_id}) => {
return (await MongoDBRoleTypes.find({role_type_id: _id}).toArray()).map(prepare)
},
},
When I query now with:
{
getUser(_id: "5d555adcd2c22a242863f7a1") {
firstname
roles {
_id
role_type_id
user_id
role_types {
name
}
}
}
}
I get:
{
"data": {
"getUser": {
"firstname": "Gregor",
"roles": [
{
"_id": "5d90cf352f50882ab0ce3877",
"role_type_id": "5d90ce48b7893d19bcc328f9",
"user_id": "5d555adcd2c22a242863f7a1",
"role_types": []
}
]
}
}
}
But why is role_types empty. As you can see the role_type_id is filled. So why there is no connection.
When I watch into MongoDB I can see the Role Type of the user.
If you need more Schema/Resolver let me know.
Ok it was kind of easy to fix. Actually the Role resolver was going multiple matches. But somehow it needs to be single lookup. That does not make much sense but somehow the search for the id lookup is a single lookup. Anyway here is what I have changed and now it works properly.
Replace this:
role_types: async ({_id}) => {
return (await MongoDBRoleTypes.find({role_type_id: _id}).toArray()).map(prepare)
},
with:
role_type: async ({role_type_id}) => {
return prepare(await DBRoleTypes.findOne(ObjectId(role_type_id)))
},
and you fix this.

Apollo Query with param

I would like to add parameter on Query using react-apollo.
My actual query is this :
const GET_USER_PLAYIST = gql`
query Playlist($id: ID!) {
playlists(where: { users: { id: $id } }) {
name
users {
id
}
}
}
`;
But it doesn't work (i receive error 400 :/). But, with "static" query, it works as expected :
{
playlists(where: { users: { id: $id } }) {
name
users {
id
}
}
I do not really understand why it doesn't work with query params.
Anyone can help me?
Thank you community!

Enumerating all fields from a GraphQL query

Given a GraphQL schema and resolvers for Apollo Server, and a GraphQL query, is there a way to create a collection of all requested fields (in an Object or a Map) in the resolver function?
For a simple query, it's easy to recreate this collection from the info argument of the resolver.
Given a schema:
type User {
id: Int!
username: String!
roles: [Role!]!
}
type Role {
id: Int!
name: String!
description: String
}
schema {
query: Query
}
type Query {
getUser(id: Int!): User!
}
and a resolver:
Query: {
getUser: (root, args, context, info) => {
console.log(infoParser(info))
return db.Users.findOne({ id: args.id })
}
}
with a simple recursive infoParser function like this:
function infoParser (info) {
const fields = {}
info.fieldNodes.forEach(node => {
parseSelectionSet(node.selectionSet.selections, fields)
})
return fields
}
function parseSelectionSet (selections, fields) {
selections.forEach(selection => {
const name = selection.name.value
fields[name] = selection.selectionSet
? parseSelectionSet(selection.selectionSet.selections, {})
: true
})
return fields
}
The following query results in this log:
{
getUser(id: 1) {
id
username
roles {
name
}
}
}
=> { id: true, username: true, roles: { name: true } }
Things get pretty ugly pretty soon, for example when you use fragments in the query:
fragment UserInfo on User {
id
username
roles {
name
}
}
{
getUser(id: 1) {
...UserInfo
username
roles {
description
}
}
}
GraphQL engine correctly ignores duplicates, (deeply) merges etc. queried fields on execution, but it is not reflected in the info argument. When you add unions and inline fragments it just gets hairier.
Is there a way to construct a collection of all fields requested in a query, taking in account advanced querying capabilities of GraphQL?
Info about the info argument can be found on the Apollo docs site and in the graphql-js Github repo.
I know it has been a while but in case anyone ends up here, there is an npm package called graphql-list-fields by Jake Pusareti that does this. It handles fragments and skip and include directives.
you can also check the code here.

Relation GraphQL

Trying to implement join but always getting null.
type User {
id: Int!
username: String!
recipes: [Recipe]
}
type Recipe {
id: Int!
title: String!
author: User
}
So basically i want to get data something like this:
User {
username,
recipes: [{//recipe}, {//recipe}]
}
And for Recipe i expecting
Recipe {
title,
author: {//user}
}
So i have query like below, and i want to get all recipes from database with included user
type Query {
recipes: [Recipe!]!
}
Here is my GraphiQL query
{
recipes {
id,
author {
id,
username
}
}
}
But in response i have author: null
{
"data": {
"recipes": [
{
"id": 1,
"author": null
}]
}
}
Any suggestions? Thanks!
Maybe somebody will face with similar issue.
Have fixed this. As said #Daniel Rearden in comments - yes issue was in resolver.
So you have to add this fields to resolver:
const resolverFunctions = {
User: {
recipes(author) {
return author.getRecipes();
}
},
Recipe: {
author(recipe) {
return recipe.getUser();
}
}
}
After you will get data what i needed above.

Any reason I am getting back the query name in the GraphQL results?

Using the makeExecutableSchema with the following Query definition:
# Interface for simple presence in front-end.
type AccountType {
email: Email!
firstName: String!
lastName: String!
}
# The Root Query
type Query {
# Get's the account per ID or with an authToken.
getAccount(
email: Email
) : AccountType!
}
schema {
query: Query
}
And the following resolver:
export default {
Query: {
async getAccount(_, {email}, { authToken }) {
/**
* Authentication
*/
//const user = security.requireAuth(authToken)
/**
* Resolution
*/
const account = await accounts.find({email})
if (account.length !== 1) {
throw new GraphQLError('No account was found with the given email.', GraphQLError.codes.GRAPHQL_NOT_FOUND)
}
return account
}
}
}
When I query with:
query {
getAccount(email: "test#testing.com") {
firstName
lastName
}
}
I am getting the following result in GraphiQL:
{
"data": {
"getAccount": {
"firstName": "John",
"lastName": "Doe"
}
}
}
So, any reason I am getting this "getAccount" back in the result?
Because getAccount is not a query name. It's just a regular field on the root query type Query.
And having results on the exact same shape as the query is one of the core design principles of GraphQL:
Screenshot from http://graphql.org/ site
Query name in GraphQL goes after query keyword:
query myQueryName {
getAccount(email: "test#testing.com") {
firstName
lastName
}
}

Resources