I am using the following GraphQL schema and want to find out how to get all the countries based on the continent code.
https://countries.trevorblades.com/
query GetCountriesByContinent($code: String!) {
countries(filter: {
continent: {
???
}
})
}
Any ideas?
UPDATE: The following code works but I am not sure how continent is match against the code.
query GetCountriesByContinent($code: String!) {
countries(filter: {
continent: { eq: $code }
}) {
name
}
}
UPDATE 2:
It might be that behind the scene when you compare a type with something it always compare using the ID field.
To better understand your query let's break it down
countries(filter: {
continent: { eq: $code }
})
countries - find all countries
filter - filtered by
continent - continent (field)
eq - equals to
$code - code (passed as argument)
In this API field code acts as an ID so behind the scenes they compare by continent.code. That logic of comparison and filtering is happening on the server-side implementation. The developer of that API can choose how he wants to implement comparison
You can also explore docs and schema on the right-side panel in Grahpql Playground and you can see possible options:
input CountryFilterInput {
code: StringQueryOperatorInput
currency: StringQueryOperatorInput
continent: StringQueryOperatorInput
}
That means you can filter countries by code currency and continent
input StringQueryOperatorInput {
eq: String
ne: String
in: [String]
nin: [String]
regex: String
glob: String
}
eq: is exactly the filter value.
ne: is anything except for the filter value.
in: matches any element in given array
nin: matches none of the elements in given array
lt: is lower than the filter value
lte: is lower than or equal to the filter value
gt: is greater than the filter value
gte: is greater than or equal to the filter value
regex: matches given JavaScript regex
glob: matches given micromatch pattern
It looks like query filters used in Gatsby to get more details
Reference docs: https://www.gatsbyjs.com/docs/query-filters/#supported-comparators
Related
I have a graphQL server consumed by many clients and have a process that generates operations from introspection; problem is that the schema has a handful of nested queries that take arguments that I may or may not want to invoke.
given this generated operation
query Query($input: String!) {
things(input: $input) {
item1
item2
nestedQuery(nestedInput: $nestedInput) {
nestedItem1
}
}
}
is there a tool (other than string parsing, that's a given) to strip unwanted fields from here so that the query is transformed into
query Query($input: String!) {
things(input: $input) {
item1
item2
}
}
Looking at the introspection JSON I can identify this item by the presence of args on the field things that is past the first depth - but I don't want to necessarily lose information on generation - I'd like those nested queries to be visible/documented.
I still don't understand how you are generating the GraphQL document here, but assuming that you have total control over it, you can use the default directives (#skip and #include) to skip or include fields based on a condition.
For example, the following document will skip the nestedQuery field when executing. You may use a variable value as the value for the argument if.
query Query($input: String!) {
things(input: $input) {
item1
item2
nestedQuery(nestedInput: $nestedInput) #skip(if: true) {
nestedItem1
}
}
}
I'm currently trying to filter entries with a field references, many.
In other words, the field takes multiple locations with each locations consisting of city among other fields.
For my query I want to get every entry that has a location with a specific city name set.
The following query filters an entry that takes only on reference for location, how would it look like when having many?
export const NEWS_ARTICLES = gql`
query GetNewsArticles($location: String) {
entryCollection(
where: {
location: { city: $location }
}
) {
items {
location
}
}
}
`;
Pulling GraphQL's schema all I get is locationCollection_exists - is this even possible?
I found the following article, which seems to do what I desire, but for the Filter API and not GraphQL: https://www.contentful.com/developers/docs/concepts/relational-queries/
Contentful DevRel here. 👋
Filtering by a linked collection entry is not supported right now. What you can do though it flip the query around.
export const NEWS_ARTICLES = gql`
query GetNewsArticles($location: String) {
cityCollection(
# your filter
) {
items {
linkedFrom {
# all the entries linking to this entry
}
}
}
}
`;
You can find more information about this approach in the docs or this blogpost.
I am creating a query in graphql + apollo client whose filters and orders can change depending on what the customer selects in the frontend. For example:
query (
$orderPart: String!
$wherePart: String!
) {
getProductInfo(
order {$orderPart}
where {$wherePart}
) {
productID
description
size
model
cathegoryNumber
}
Where $orderPart will be equal to "description: DESC" or "productID: ASC" (depending what the customer selected in a momento or another). And $wherePart will be equal to "cathegoryNumber: {eq: 12}" or "productID: {eq: 111111}".
I need to pass the order/filter clause completely as a parameter.
But it doesn't work. Syntax is error "Syntax Error: Expected name, found $".
So my question is...
Is there any way to implement these dynamic filters/orders? How could this functionality be implemented? Is there any other way to implement this dynamic filters and orders?
Thanks.
Note:
In the official documentation, I found that only values can be passed as a parameters:
query (
$orderValue: sortEnumType! = DESC
$whereValue: String! = "description1"
) {
getProductInfo(
order {productID: $orderValue}
where {description: {eq: $whereValue} }
) {
productID
description
size
model
cathegoryNumber
}
But that is not what I need because always filters/orders couldn't be changed. And they could be completely different each time (prodyuct:ASC) first time, (cathegoryNumber:DESC) second time, etc...
Thanks for your help, I found a solution. Using apollo client and variables when the template is created:
let orderValue = 'order {productID: ASC}'; // built dynamically
let whereValue = 'description: {eq: "description1"}'; // built dynamically
document = gql`
query {
getProductInfo(
${orderValue}
${whereValue}
) {
productID
description
size
model
categoryNumber
}
`;
Let's say that I want to get a person's age using this query:
{
getUser(id: "09d14db4-be1a-49d4-a0bd-6b46cc1ceabb") {
full_name
age
}
}
I resolve my getUser query like this (I use node.js, type-graphql and knex):
async getUser(getUserArgs: GetUserArgs, fields: UserFields[]): Promise<User> {
// Return ONLY ASKED FIELDS
const response = await knex.select(this.getKnexFields(fields)).from(USER).whereRaw('id = ?', [getUserArgs.id]);
// returns { full_name: 'John Smith' }
return response[0];
}
The problem is that then I can't calculate age field, because I did not get born_at (datetime field stored in a db) in the first place:
#FieldResolver()
age(#Root() user: User, #Info() info: GraphQLResolveInfo): number {
console.log(user); // { full_name: 'John Smith' } no born_at field - no age, so error
// calculate age from born_at
return DateTime.fromJSDate(user.born_at).diff(DateTime.fromJSDate(new Date()), ['years']).years;
}
Is there some fancy graphql-build-in way / convention to predict that born_at will be needed instead of doing it manually through info / context?
You should always return full entity data from the query-level resolvers, so they are available for field resolvers.
The other solution is to manually maintain a list of required fields for field resolvers, so your "fields to knex" layer can always include them additionally".
Further improvements might be to can a list of additional columns based on the requested fields (thus the field resolvers that will be triggered).
How can you filter by dates in Gatsby? The docs allude to lt and gt operators, I get errors when I try to use them.
Filtering by date in Gatsby is potentially tricky. Many API's send dates in JSON as strings - in the ISO8601 format. That means that GraphQL will treat the dates as strings too. This is fine if you are happy filtering on string equality, but that's not usually how you want to filter on dates.
A common use case is to filter to dates that are in the past or future. In most situations, we would do some kind of less than or more than comparison with todays date. Unfortunately, this won't work for dates strings in GraphQL. The lt and gt operators only apply to numbers and won't work for strings.
Fortunately, there is an escape hatch - setFieldsOnGraphQLNodeType. This allows us to take a content node, and add our own fields with derived data in. We can take a datestring, and parse it to a timestamp - a number. With the date as a timestamp, graphql can do its thing and allow lt and gt filters.
Lets say we are writing a blog, and what to filter posts that are published in the past. We can add a publishedAt datetime field in our ContentModel, which will help our content authors publish things in the future. We can filter out the future posts until we transform publishedAt from a date string into a number.
Here's how that looks:
exports.setFieldsOnGraphQLNodeType = ({ type }) => {
if (type.name === `ContentfulBlogPost`) {
return {
publishAtTimestamp: {
type: GraphQLFloat,
resolve: source => {
return new Date(source.publishAt).getTime();
}
}
};
}
// by default return empty object
return {};
};
ContentfulBlogPost 's now have a new field publishedAtTimestamp which is a number, that means you can now filter on it with lt or gt
query {
allContentfulBlogPost(
filter: { publishedAtTimestamp: { lt: $SOME_TIMESTAMP } }
) {
edges {
node {
id
...otherFields
}
}
}
}