Why can't i filter a Deep nested query in graphql? - graphql

So i just started using graphql recently (last week to be precise). I get the concept of being able to filter queries with the 'where' argument and all but i noticed when i try to get objects from a deep nested query it becomes somewhat impossible. So say i have 'domestic_worker_nextofkin' query that should get fullname, mobile_phone1, and relationship where 'archived' _is_null equals true as given below:
domestic_workers_nextofkin(where: {archived:{_is_null: true}}){
full_name
mobile_phone1
domestic_workers_relationships{
relationship
}
}
}
The query above does it's intended job and gets the full_name, mobile_phone1 and relationship.
But my current problem is that when this query is deeply nested as shown below (the asterisked code):
query User($userId: Int) {
domestic_workers_news{
title
date_created
summary
url
}
users_user(where: {id: {_eq: $userId}}) {
domestic_workers_pictures(order_by: {id: desc}, limit: 1) {
id
}
id
password
username
first_name
last_name
email
gender
birth_date
mobile_phone1
mobile_phone2
home_address_street
home_address_town
home_address_lga
home_address_state
home_address_country
home_address_postal_code
job_title
workplace
verified
agreed_terms
date_joined
last_modified
domestic_workers_workers {
domestic_workers_pictures(order_by: {id: desc}, limit: 1) {
id
}
id
first_name
last_name
other_name
email
mobile_phone1
mobile_phone2
home_town
home_state
service
birth_date
gender
date_created
current_employer_id
domestic_workers_relationships{
id
payment
payment_currency
start_date
relationship
domestic_workers_agent {
full_name
mobile_phone1
domestic_workers_relationships{
relationship
}
domestic_workers_pictures(order_by: {id: desc}, limit: 1) {
id
}
}
**domestic_workers_nextofkin (where: {archived:{_is_null: true}}) {
full_name
mobile_phone1
domestic_workers_relationships{
relationship
}
}
}**
domestic_workers_reviews {
id
score
summary
date_created
users_user {
first_name
last_name
domestic_workers_pictures(order_by: {id: desc}, limit: 1) {
id
}
}
}
employerRelationships: domestic_workers_relationships(order_by: {id: desc}, limit: 1, where: {relationship: {_eq: "Employer"}}) {
end_date
relationship
}
}
}
}
It shows the 'where' argument highlighted as red, which possibly means that the 'where' argument shouldnt be placed there which seems rather confusing to me. Can anyone explain why this happens and show me a workaround to pull off the task i'm trying to perform? Thanks.

From the docs:
The where argument can be used in array relationships as well to filter the nested objects. Object relationships have only one nested object and hence they do not expose the where argument.
users_user is an object relationship (it returns a single object instead of an array of them), so it cannot be filtered.

Related

Search By Column in Laravel/Lighthouse GraphQL API

currently i'm creating a GraphQL implementation of an existing API.
i want to create Search Function not with primary column, which is not id, but id_position.
here is my scheme :
type Query #guard {
subordinate(
positionId: ID
): [Employee!]! #all
}
type Position #key(fields: "id") {
id: ID
name: String
}
"Account of a person who utilizes this application."
type Employee #key(fields: "id") {
id: ID
name: String
id_position: Int
}
but, when I run this :
query EmployeeSubordinate($id: ID) {
subordinate(positionId: $id) {
name
}
}
{
"id" : 93
}
I ve got result all rows of employee, not employee with id_position = 93
how to solve this?
I think the problem is here
type Query #guard {
subordinate(
positionId: ID
): [Employee!]! #all
}
The #all is getting all records from DB #all docs
The correct way is this
type Query #guard {
subordinate(
positionId: ID
): Employee
}
I removed ! from Employee because your ID is not required, so in some cases it masy return null, i you handle like thatin backend.
And alsoe I removed [] because you no longer getting many Employee you just getting one.

Graphql syntax for single query for same field with different parameters from an array

I am looking for something like the below pseudo query:
query users($ids: [String!]) {
"id from $ids": getUser(id){
id
name
dob
}
}
To get a response like:
data: {
'039ccf5c-3070-4368-b790-0884669e759d': {id: '039ccf5c-3070-4368-b790-0884669e759d', name: 'u1', 'dob': 12-12-12'},
'139ccf5c-3070-4368-b790-0884669e759d': {id: '139ccf5c-3070-4368-b790-0884669e759d', name: 'u1', 'dob': 12-12-12'},
}
Is this possible?
You can use aliases to query to the same field multiple times:
query users($id1: String!, $id2: String!) {
user1: getUser(id: $id1) {
...UserFragment
}
user2: getUser(id: $id1) {
...UserFragment
}
}
fragment UserFragment on User {
id
name
dob
}
There are no control structures in GraphQL, so there's no way to loop through a value that is a list. If your list of IDs is of variable length, then you'll have to construct a query similar to the above programmatically, dynamically generating both the variable definitions and the aliased fields.

How can i search by field of joined table in graphql and nestjs

i create two table tag and tagTranslation.
following is field of each
Tag
id, type, transloations, creaed_at, updated_at
TagTranslation
id, tag_id, name, language
I use graphql, i want to get tag list by type, name and language
{ tags(name:"tag1", language:"en, type:3){
id,
type,
translations{
id,
name,
language,
}
}
}
so I create resolver like following
#Query(returns => [Tag])
tags(#Args() tagArgs: TagArgs): Promise<Tag[]> {
const where = {
...(tagArgs.type) && {type: tagArgs.type}
};
const include_where = {
...(tagArgs.name) && {name: { [Op.like]: `%${tagArgs.name}%` }},
...(tagArgs.language) && {language: tagArgs.language}
};
return this.tagService.findAll({
where: where,
include: {
as: 'translations',
model: TagTranslation,
where: include_where,
required: true,
}
});
}
#Query(returns => Tag)
tag(#Args({name: 'id', type: ()=> Int}) id: number): Promise<Tag>{
return this.tagService.get(id)
}
#ResolveProperty()
async translations(#Parent() tag): Promise<TagTranslation[]>{
const { id } = tag;
return await this.tagTranslationService.findAll({tag_id: id});
}
when i call tags, the query is called twice
first, A query is executed to get the results I want.
but second,
SELECT `id`, `tag_id`, `name`, `language`, `created_at`, `updated_at` FROM `tag_translation` AS `TagTranslation` WHERE `TagTranslation`.`tag_id` = 1;
query is called once more, so i can't get results what i want.
I think second query is called because of ResolveProperty, I remove ResolveProperty. after that, tag query is not include tagtranslation info...
how can i solve that problem ? or is there another idea??
how can i solve that problem ? or is there another idea??
Relations between entities should be resolved on a field resolver (#ResolveProperty()) level because when someone requests only id and type, you will still perform additional, not needed join on TagTranslation in sql query.

How to reshape a GraphQL (via Hasura) query response?

I have a CHAT_MESSAGE_FRAGMENT that returns all the message data from my Hasura graphql api.
However, the Gifted Chat react-native component requires the data in a specific structure so I'm attempting to convert it with the query below.
I'm able to alias all the top level data but can't figure out how to add a nested level of data.
I'm guessing it isn't possible but I thought I'd ask in case I'm missing something.
const GIFTED_CHAT_GROUP_MESSAGES_QUERY = gql`
query chatGroupMessages($chatGroupId: Int!) {
chat_message(
where: { to: { id: { _eq: $chatGroupId } } }
) {
_id: id,
# user: {
# _id: from.id, <== How do I add
# name: from.name, <== this secondary level?
# },
text: message,
image: image_url,
createdAt: created_at,
system: message_type,
}
}
${CHAT_MESSAGE_FRAGMENT}
`;
Assuming you already have chat_message.user_id -> users.id foreign key constraint set up, you'll also need to alias the from object in addition aliasing any of its nested fields:
const GIFTED_CHAT_GROUP_MESSAGES_QUERY = gql`
query chatGroupMessages($chatGroupId: Int!) {
chat_message(
where: { to: { id: { _eq: $chatGroupId } } }
) {
_id: id,
from: user: {
_id: id,
name
},
text: message,
image: image_url,
createdAt: created_at,
system: message_type,
}
}
${CHAT_MESSAGE_FRAGMENT}
`;
The secondary level of data is basically nested object queries in Hasura. You can nest any number of queries as long as a relationship has been created.
In this case, assuming the chat_message table has a user_id field, you can establish a foreign key constraint for chat_message.user_id -> users.id, where users is a table with id as primary key.
Once the foreign key constraint is created, Hasura Console automatically suggests relationships. Here user would be an object relationship in chat_message table.
Here's the official docs link for Creating a relationship

GraphQL: Querying for a value from another table from a mutation

Let's say I have a table t1 that is foreign key'd to another table t2. For simplicity, t2 only has columns 'name' and 'id' which are both unique. I store the id in t1.
My problem is I want to write a mutation where I know the name but I don't know the id when I go to store something in t1. Is there a way to query inside of my mutation so that it converts the value in my statement?
Perhaps a plugin I can add to my project?
I end up with something like this where I pass in a known name but I want to store the id
mutation addT1(
$knownT2Name: String!,
) {
createT1 (
input: {
t1: {
id: $component
# Is there a way to convert this to the id inside the query
# Or do I need to query for the id with the name first then pass that in?
t2_id: $knownT2Name
}
}
) {
t1 {
id
t2_id
}
}
}
This is a simple example. The reason I don't want to query for the id with the name is in actuality t1 is foreign key'd to a myriad of other tables with the same situation and I don't want to do 9+ queries just to convert each string to an integer id.
I would much rather be able to do something like this:
mutation addT1(
$knownT2Name: String!,
) {
createT1 (
input: {
t1: {
id: $component
t2_id: t2Byt2(name: $knownT2Name) { id }
}
}
) {
t1 {
id
t2_id
}
}
}
Where t2Byt2(name: $knownT2Name) { id } would be a sub-query that passes the name and gets the id, then stores the id in 't2_id'
I'm looking at a nested mutations plugin for postgraphile (Here's the GitHub)but I haven't had any traction. It's not quite what I'm looking for.
For the simple relationship I believe you want something like: (using the nested mutations plugin). This only works on CREATE. No luck with an UPSERT.
mutation addT1($t1Name: String!, $t2Name: String!) {
createT1(
input: {
T1: {
name: $t1Name,
t2ToT2: { connectByT2: { name: $t2Name } }
}
}
) {
t1 {
t1Id
name
t2ByT2 {
name
}
}
}
}

Resources