How to query Graphql 2 objects with the same argument - javascript

I'm implementing GraphQL to query data from the web with web driver.
My problem is that I cannot figure out how to use one argument as input for 2 different queries. So basically It is querying data from 2 different sites and has the same input which is usually 4 character Symbol.
What I want my query to look like.
{
Webpage1(symbol:"AABC"){
data_from_site,
some_other_data
Webpage2(symbol:"AABC"){ ##get rid of this Double attribute entry
data_from_page2
}
}
}
How can I pass only one argument be And get data from both sites?
So it will be in the root context for the resolver to use.
I'm fairly new to GraphQL and have tried defining separate GraphQLObjectType in order to solve this problem. But what I'm really looking for is unified data in the same object and arguments parsed from the parent object.
var schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
fields: {
Webpage1: {
type: Website1,
args: {
symbol: { type: GraphQLString },
//date: { type: GraphQLString }
},
resolve: function (_, { symbol }) {
return {
symbol
};
}
},
Webpage2: {
type: History,
resolve: function (_, { symbol }) {
return {
symbol
};
}
}
}
})
})

If I'm understanding your question correctly, you can keep your schema as is and just utilize a variable when sending your query:
query MyQuery($mySymbol: String){
Webpage1(symbol:$mySymbol) {
data_from_site
some_other_data
}
Webpage2(symbol:$mySymbol) {
data_from_page2
}
}
Variables are defined at the top of your document, as part of your operation definition. Once defined, they can used any number of times inside the document anywhere you would use the same kind of literal value. You can check out the official tutorial on variables here and the spec here.

Related

Get alias name in result from mongoose query

I am trying to use alias names for crud operations. It only works well for create query. But for find and findOne I am using translateAliases in hooks. Main issue is for read query, for find and findOne result, the result does not contain alias name, but I need them.
This is my schema:
const someSchema = new mongoose.Schema({
f1: {
type: Number,
default: -1,
alias: 'field1'
},
f2: {
type: Boolean,
default: false,
alias: 'field2'
}
}, {
timestamps: true
});`
If I am saving data with alias names, it is working, but for fetching/querying. I am using hooks:
`someSchema.pre('find', function() {
this.model.translateAliases(this.getQuery());
});
someSchema.pre('findOne', function() {
this.model.translateAliases(this.getQuery());
});
Now what I want is in result from these queries, the data should contain alias name.

JSON type object only has parse and stringify methods, but I want to access the objects data

I have a project with NestJS, Typescript and Typeorm. I'm working with the following class Entity
class Event {
user: string,
createdAt: Date,
type: string,
data: JSON
}
In one of my methods I'm making a query to get some events, but I want to access just a few properties of the data attribute because the object has a lot information I don't really need. The problem is that when I try to access the json, for example: receivedEvent.data.myProperty typescript tells me that this property is not available in type JSON. The only solution I can think of is changing the type of the data attribute to a string and parse it to json after the query, but I want to know if there is any other solution to this. This is the code I'm using to query the events:
async getLogs(loanId: string): Promise<Event[]> {
const events = await this.eventRepository.find({
select: ['createdAt', 'user', 'type', 'data'],
where: {
type: In([
'early_payoff',
]),
data: Raw(
/* istanbul ignore next */
() => 'data->"$.GUID" = :id',
{ id: loanId },
),
},
order: {
id: 'DESC',
},
});
console.log(events);
return events.map(e=>{
/// This is where my problem is
const json: any = {"withdrawReason": e.data.withdrawReason}
return {...e, data: json}
});
}
I found a quick to solution to this problem. I set the event.data to another variable with type and after that Typescript doesn't throws error.
return events.map(e=>{
/// This is where my problem was
const json: any = e.data
const jsonData: any = {"withdrawReason": json.withdrawReason}
return {...e, data: jsonData}
});

How can I pass an array of objects into Query?

I'm trying to figure out how to pass an array of objects into my GraphQL query, however i'm finding the documentation a little unclear on how to do so. I'm working with Apollo in the FE, Graphql-yoga in the BE and using Prisma as my database along with their API.
Here is my query with the array of objects hard coded:
const USERS = gql`
query USERS(
$userId: ID
) {
users(
where: {
id_not: $userId
hasProducts_some: {
OR: [
{ itemId: 1 },
{ itemId: 2 }
]
}
}
) {
firstName
}
}
`;
The above query returns me what I want, where i'm a bit stuck is how to get this array:
[
{ itemId: 1 },
{ itemId: 2 }
]
passed in as a variable of the query. From what I could find online, I might need to create a GraphQLObjectType on the client side to be able to pass in an object definition. Here was my implementation of that:
import { GraphQLObjectType, GraphQLString } from 'graphql';
const ProductName = new GraphQLObjectType({
name: 'ProductName',
fields: () => ({
itemId: {
type: GraphQLString,
},
})
});
const USERS = gql`
query USERS(
$userId: ID,
$hasProducts: [ProductName]
) {
users(
where: {
id_not: $userId
hasProducts_some: {
OR: $hasProducts
}
}
) {
firstName
}
}
`;
The above returns me the following error:
Unknown type "ProductName"
Have I gone with the correct approach here for passing in arrays of objects, if so what's wrong with my implementation?
Types are created and used in creating your schema server-side. Once created, the schema cannot be modified at runtime -- it has whatever types and directives were specified when it was created. In other words, defining a new type on the client-side is meaningless -- it can't be used in any queries you send to the server since the server is not aware of the type.
If a variable (like $hasProducts) is passed to an argument (like hasProducts_some), that variable's type must match the type of the argument. This type could be a scalar (like String or Int) or it could be an input object type. What exact type that that is depends on the schema itself. To determine the type to use, you can open up your schema's documentation in GraphQL Playground (or GraphiQL) and search for the field in question (in this case, hasProducts_some).
Note that you can also just pass a single variable in for the whole where field.
Since the gql function expects a template literal, you should escape the product object like so:
const USERS = gql`
query USERS(
$userId: ID,
$hasProducts: [${ProductName}]
) {
users(
where: {
id_not: $userId
hasProducts_some: {
OR: $hasProducts
}
}
) {
firstName
}
}
`;
New to graphql. But was wondering if this can resolve it.
const USERS = gql`
query USERS(
$userId: ID,
$hasProducts: GraphQLList(ProductName)
) {
users(
where: {
id_not: $userId
hasProducts_some: {
OR: $hasProducts
}
}
) {
firstName
}
}
`;
Minor change, but am not privileged to comment . So posting it as answer.

What does the interfaces in GraphQLInterfaceType?

I have the following the code snippet:
export const NodeInterface = new GraphQLInterfaceType({
name: 'Node',
fields: {
id: {
type: new GraphQLNonNull(GraphQLID)
}
},
resolveType: (source) => {
if (source.__tableName === tables.users.getName()) {
return UserType;
}
return PostType;
}
});
and a GraphQLObjectType that is using the interface:
export const PostType = new GraphQLObjectType({
name: 'Post',
interfaces: [ NodeInterface ],
fields: {
id: {
type: new GraphQLNonNull(GraphQLID),
resolve: resolveId
},
createdAt: {
type: new GraphQLNonNull(GraphQLString),
},
body: {
type: new GraphQLNonNull(GraphQLString)
}
}
});
For what do I have to define an interface?
In GraphQL, interfaces fulfill two purposes:
They ensure that the types implementing them also implement specific fields. For example, the Node interface here has an id field -- that means any type that implements the Node interface will also need to have an id field (and that id will need to be an ID scalar like in the interface) The same goes for arguments on those -- any arguments on the fields in the interface will also have to exist on the matching fields in the implementing type.
They can be used when two or more types are expected for a field. A field will always resolve to exactly one type or scalar, however, by using interfaces (or unions) we indicate in our schema that the field could resolve to one of a set of types.
So let's say we have a Node like in your snippet, some types that implement it, and a query that returns a Node:
interface Node {
id: ID!
}
type Foo implements Node {
id: ID!
someFooField: String!
someOtherFooField: Int!
}
type Bar implements Node {
id: ID!
someBarField: String!
someOtherFooField: Int!
}
type Query {
getNode(id: ID!): Node!
}
In our example, getNode could resolve to either a Foo or a Bar. When we write our query, we don't know which one will be resolved. But because we know the id field is required by the interface, we can write a query like this:
query OperationName {
getNode(id: "SOME_ID"){
id
}
}
If we need to query someBarField as well, though, we can't do this:
query OperationName {
getNode(id: "SOME_ID"){
id
someBarField
}
}
because Foo doesn't have that field. Instead we have to utilize a fragment, like this:
query OperationName {
getNode(id: "SOME_ID"){
id
... on Bar {
someBarField
}
}
}
Then someBarField will be returned, but only if the field resolves to the type Bar. If it's a Foo, only id will be returned. Similarly, you can request non-shared fields from any type implementing the same interface:
query OperationName {
getNode(id: "SOME_ID"){
id
... on Bar {
someBarField
}
... on Foo {
someFooField
}
}
}
Last but not least, it should be mentioned that unions work in a very similar fashion. However, unlike interfaces, there are no shared fields defined for a Union, so a type does not "implement" a union, it just is part of one. That means when requesting a field that returns a union, you'll always have to use fragments since there are no shared fields to request.

GraphQL nested query definition

I'm trying to create tree-like structure for my queries, to get rid off queries like
peopleList, peopleSingle, peopleEdit, peopleAdd, peopleDelete companyList, companySingle, companyEdit, companyAdd, companyDelete etc.
In the end I would like to send query like this:
query test {
people {
list {
id
name
}
single(id: 123) {
id
name
}
}
company {
list {
id
name
}
single(id: 456) {
id
name
}
}
}
mutation test2 {
people {
create(data: $var) {
id
name
}
}
people {
edit(id: 123, data: $var) {
id
name
}
}
}
This is part of my query object on people module:
people: {
type: //What type this should be?
name: 'Root of People queries',
fields: () => ({
list: {
type: peopleType,
description: 'Returns all people in DB.',
resolve: () => {
// resolve method implementation
}
},
single: {
type: peopleType,
description: 'Single row from people table. Requires ID argument.',
args: {
id: { type: new GraphQLNonNull(GraphQLID) }
},
resolve: () => {
// resolve method implementation
}
}
})
}
I have tried to put this snippet into GraphQLObjectType and then combine them together in RootQuery (using GraphQLObjectType again) - didn't work.
Alternative method could be to create new Type - like peopleQueriesType, inside this type specify all my queries as fields and then create single query for this object. But this seems odd to me - polluting my code with unnecessary objects just to merge my queries in tree-like shape.
I have tried to look at Apollo server implementation, if it can do this kind of query structure, but couldn't find any help in documentation.
I'm using node.js + express + graphql-js on my server.
Short answer:
type should be a GraphQLObjectType containing all the fields like this:
type: new GraphQLObjectType({ name: 'patientQuery', fields: { find, findOne } })
Details: I ended up with this query using the code below:
{
patient {
find {
id
active
}
findOne(id: "pat3") {
id
active
}
}
}
in patient/queries/index.js I have this
import findOne from './find-one.js';
import find from './find.js';
import { GraphQLObjectType } from 'graphql';
export default {
patient: {
type: new GraphQLObjectType({ name: 'patientQuery', fields: { find, findOne } }),
resolve(root, params, context, ast) {
return true;
}
}
};
then in queries.js
import patient from './patient/queries/index.js';
export default {
...patient
};
and finally my schema schema.js that is passed to graphql express server
import {
GraphQLObjectType,
GraphQLSchema
} from 'graphql';
import queries from './queries';
import mutations from './mutations';
export default new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
fields: queries
}),
mutation: new GraphQLObjectType({
name: 'Mutation',
fields: mutations
})
});

Categories