How to pass the result of one field to another in graphql - graphql

I have a query which gives me the list of projects for which I am using project schema. I want to get the count of repeated users across the projects for which I am calling a function getRepeatedUsersCounter. But I am not sure how do I pass this projectList result to this getRepeatedUsersCounter() and get it fit in the below query structure
query projectList() {
getProjectList() {
project{
id
name
users
}
usersCounter{
//This is for across the project
user1Counter
user2Counter
}
}
}

Related

GraphQL Tag dynamic table name in query (apollo)

In my app every customer has a own table for its data. Depending on which customer was selected I want to dynamically build the tablename for the Graphql query.
For example:
// Query for customer 1
gql`
query overviewQuery {
customer_1 {
aggregate {
count
}
}
}
`
// Query for customer 2
gql`
query overviewQuery {
customer_2 {
aggregate {
count
}
}
}
`
I have the customer id in my vuex store and want to insert a variable into the query like in the following pseudocode which is not working.
const tblUserAggregateName = `customer_${this.$store.state.customer.customerId`
gql`
query overviewQuery {
${this.tblUserAggregateName} {
aggregate {
count
}
}
`
Is there an option how to do this or how can this problem be solved?
It is not an option to hardcode all different customer queries and selected them on runtime.
Thanks!
In the answers it was mentioned, that it is against best practice to dynamically change the table name of GraphQL queries.
As changing the complete database structure for all clients (they each have a separate Database with a own PostgreSQL schema name) is not an option, I found a solution the looks a little bit hacky and definitely not best practice but I thought I might be interesting to share for others with the same problem.
The approach is pretty easy: I write the query as a simple string where I could use variables and convert them later to the gql AST Object with graphql-tag
const query = () => {
const queryString = `
{
${customerId}_table_name {
aggregate {
count
}
}
}`
return gql`${queryString}`
}
Works, but I you have a better solution, I am happy to learn!
You can supply variables, but they should not be used to dynamically infer schema object names. This violates core concepts of GraphQL. Try this instead:
gql`
query overviewQuery ($customerId: ID!) {
customerData (id: $customerId) {
tableName
aggregate {
count
}
}
}`
Apollo provides great documentation on how to supply variables into a query here: https://www.apollographql.com/docs/react/data/queries/
The backend can then use the customerId to determine what table to query. The client making requests does not need to know (nor should it) where that data is or how it's stored. If the client must know the table name, you can add a field (as shown in the example)

How to force a filter on server side to a graphql query?

Imagine the condition that I have a query called "users" that returns all the users and these users can be associated with one or more companies, so I have a type UserCompanies (I need it because it saves some more information beyond the relation). I'm using Prisma and I need to force a filter that returns only users that are of the same company as the requester.
I get the information of the company from JWT and need to inject this to the query before sending it to Prisma.
So, query should be like that:
query allUsers {
users {
name
id
status
email
userCompanies{
id
role
}
}
}
and on server side, I should transform it to: (user where is ok, just changing args)
query allUsers {
users(where: {
userCompanies_some: {
companyId: "companyId-from-jwt"
}
}) {
name
id
status
email
userCompanies(where: {
companyId: "companyId-from-jwt"
}){
id
role
}
}
}
I'm seeing a few resolutions to this, but I don't know if it is the best way:
1 - Using addFragmentToInfo, does the job to put conditions on the query, but if the query has a usercompanies already set, it gives me a conflict. Otherwise, it works fine.
2 - I can use an alias for the query, but after DB result I will need to edit all the results in array to overwrite the result.
3 - don't use info on Prisma and filter in js.
4 - Edit info(4th parameter) of type GraphqlResolveInfo

Best practice for schema naming of entity/collection

I am building a Graphql Schema and I was wandering what is the best practice of returning single vs collection items of a type. Let's say we want to retrieve users,
One option (if possible somehow) would be to have a query like this where the ID is optional, if ID is passed we return a single item, if not a collection of all users
query {
user (id: 1234) {
name
}
}
// return a single [User]
query {
user (id: null) {
name
}
}
// return a collection [User,User,User,...]
Another option would be to have user and users
query {
user (id: 1234) {
name
}
}
// return a single User
query {
users {
name
}
}
// return a collection [User,User,User,...]
I was wondering what is the best practice, or if you can pin-point me some resources related to that to read.
I am using the singular and plurals nouns to name the query field that return a single object and a list of object respectively. I think this naming style is very natural to most of the developers.
So to return a single user, it is :
type Query {
user(id:Int!) : User
}
It always return a single user. Just make the id input parameter as mandatory such that it cannot accept NULL.
And to return a list of user , normally it is:
type Query {
users : [User]
}
But in case it can have many users , most probably you need to consider something like pagination that allows developers to get the user page by page. For the offset -based pagination , I am doing something like below :
type Query {
users(offset:Int limit:Int) : UserPage
}
type UserPage {
data : [User]
pageInfo : PageInfo
}
type PageInfo {
# When paginating forwards, are there more items?
hasNextPage : Boolean!
# When paginating backwards, are there more items?
hasPreviousPage: Boolean!
# Total number of records in all page
total : Long
}
Depending on the requirements , you can consider to add an orderBy or a filter input parameter to the users query field to provide more options to the developers to get the result set that they are interested.
If you want to return the user list in the cursor-based pagination style, you can take a look on Relay Specification.

GraphQL with multiple objects: should I keep all objects in a single query?

I´m building a SaaS B2B application composed of several different objects. Examples:
Users
Customers
StockItens
StockLevels
PriceList
Sales
Returns
Etc...
I´ll have around 40 different objects, that can be listed and created, edited, and deleted individually.
Facing the GraphQL concepts for the first time, should I build a large schema for all objects, like the example below, or should I keep each object on its own query.
query {
viewer {
Users {
id
firstName
lastName
address
city
...
}
Customers {
id
firstName
lastName
address
city
rating
...
}
StockItens {
id
item_id
sales {
id
dateTime
qty
unitValue
totalValue
...
}
...
}
StockLevels {
...
}
PriceList {
...
}
Sales {
id
dateTime
qty
unitValue
totalValue
...
}
Returns {
...
}
}
}
Looking for the first option (keeping everything into one single query) seens logical as I will be using fragments to access the desired piece of information, but then I will have a huge schema with lots of inter relations.
PLease advice what would be the best practice on that use case.
I suggest you do not write a query where you add all needed data but use the concept of fragments as you already pointed out.
And you fetch only the data which are needed for the current page. So the throughput is kept minimal.
e.g.
If you have a page where you update a user you just fetch the needed data for this user in a specialized query. The query consists of fragments.
The fragments are related to the subcomponents which are used in the page, for example a form where you show the data of the user.
The fragment of the form defines the data it needs from the user and the update page combines the fragments to the query.
// in user form component
const userFormFragments = {
name: "UserForm",
document: `fragment UserForm on User {
id
name
}`
};
// in update user page
const userQuery = `query getUserQuery($userId: ID!) {
getUser(userId: $userId) {
...${userFormFragment.name}
}
${userFormFragment.document}
}`

Can graphql return aggregate counts?

Graphql is great and I've started using it in my app. I have a page that displays summary information and I need graphql to return aggregate counts? Can this be done?
You would define a new GraphQL type that is an object that contains a list and a number. The number would be defined by a resolver function.
On your GraphQL server you can define the resolver function and as part of that, you would have to write the code that performs whatever calculations and queries are necessary to get the aggregate counts.
This is similar to how you would write an object serializer for a REST API or a custom REST API endpoint that runs whatever database queries are needed to calculate the aggregate counts.
GraphQL's strength is that it gives the frontend more power in determining what data specifically is returned. Some of what you write in GraphQL will be the same as what you would write for a REST API.
There's no automatic aggregate function in GraphQL itself.
You can add a field called summary, and in the resolve function calculate the totals.
You should define a Type of aggregated data in Graphql and a function you want to implement it. For example, if you want to write the following query:
SELECT age, sum(score) from student group by age;
You should define the data type that you want to return:
type StudentScoreByAge{
age: Int
sumOfScore: Float
}
and a Graphql function:
getStudentScoreByAge : [StudentScoreByAge]
async function(){
const res = await client.query("SELECT age, sum(score) as sumOfScore
from Student group by age");
return res.rows;
}
... need graphql to return aggregate counts? Can this be done?
Yes, it can be done.
Does GraphQL does it automatically for you? No, because it does not know / care about where you get your data source.
How? GraphQL does not dictate how you get / mutate the data that the user has queried. It's up to your implementation to get the requested aggregated data. You could get aggregated data directly from your MongoDB and serve it back, or you get all the data you need from your data source and do the aggregation yourself.
If you are using Hasura, in the explorer, you can definitely see an "agregate" table name, thus, your query would look something similar to the following:
query queryTable {
table_name {
field1
field2
}
table_name_aggregate {
aggregate { count }
}
}
In your results, you will see the total row count for the query
"table_name_aggregate": {
"aggregate": {
"count": 9973
}
This depends on whether you build the aggregator into your schema and are able to resolve the field.
Can you share what kind of GraphQL Server you're running? As different languages have different implementations, as well as different services (like Hasura, 8base, and Prisma).
Also, when you say "counts", I'm imagining a count of objects in a relation. Such as:
query {
user(id: "1") {
name
summaries {
count
}
}
}
// returns
{
"data": {
"user": {
"name": "Steve",
"summaries": {
"count": 10
}
}
}
}
8base provides the count aggregate by default on relational queries.

Resources