I am trying to implement mutations in GraphQL. I am using GraphQL Play Ground Ui for query.
Here is my mutation :
mutation{
createProduct (data :{
product: "abc",
product_status : {
"1" : {
order : "done"
}
}
Here is my TypeDef
type Product {
product : String,
product_status : JSON
}
But I am getting error in product_status excepted Name but found String as object contains 1 as string. How can i resolve this. I need to store this type of object in My database.Can someone help me to this.
Error Image
GraphQL supports strict data typing. So basically you can't have a string as a property key because that would mean it wouldn't know what to deserialize into. Also I'm not sure if JSON is a data type. I know strings and types but not JSON. You coudld have a object like:
type Product {
product : String,
product_status : ProductStatus
}
type ProductStatus {
id: ID,
order: String,
}
This is how you could design it.
Related
I was using schema.virtual property in js but now i want to use it with tyescript and getting error.
this is my code
UserSchema.virtual('fullname').get(function () {
return `${this.firstName} ${this.lastName}`
});
I am facing this error
this' implicitly has type 'any' because it does not have a type annotation.
There are a few solutions to work around this specific problem, for example declaring an interface for typing this, but in my experience this will create other issues (one being that doc.fullname will cause an error because TS isn't smart enough to know fullname has been added as a virtual).
The easiest way to solve this is to make virtuals part of the Schema declaration:
const UserSchema = new mongoose.Schema({
firstName : String,
lastName : String,
...
}, {
virtuals : {
fullname : {
get() {
return `${this.firstName} ${this.lastName}`;
}
}
}
});
I am trying to query a single MongoDB document (trivia) using GraphQL, but am having trouble with one of the document fields. It's the trivia.rounds field that should return an array of objects (either LightningRound or MultipleChoiceRound).
schema.graphql
type Trivia {
_id: String!
createdAt: String!
rounds: [Round]!
}
interface Round {
type: String!
theme: String!
pointValue: Int!
}
type LightningRound implements Round {
type: String!
theme: String!
pointValue: Int!
questions: [LightningRoundQuestion]
}
type MultipleChoiceRound implements Round {
type: String!
theme: String!
pointValue: Int!
questions: [MultipleChoiceRoundQuestion]
}
// ...
trivia.js // resolver
require('dotenv').config()
const { ObjectId } = require('mongodb')
const trivia = (app) => {
return async (root, { _id }) => {
return app
.get('db')
.collection(process.env.DB_COLLECTION_TRIVIA)
.findOne(ObjectId(_id))
}
}
module.exports = {
trivia
}
graphql query
query {
trivia(_id: "5e827a4e1c9d4400009fea32") {
_id
createdAt
rounds {
__typename
... on MultipleChoiceRound {
type
theme
}
... on PictureRound {
type
theme
}
... on LightningRound {
type
theme
}
}
}
}
I keep getting the error:
"message": "Abstract type \"Round\" must resolve to an Object type at runtime for field \"Trivia.rounds\" with value { questions: [[Object], [Object]] }, received \"undefined\". Either the \"Round\" type should provide a \"resolveType\" function or each possible type should provide an \"isTypeOf\" function."
I don't understand what it means by resolveType or isTypeOf. I've seen this in other questions, but have no clue what to implement in my setup. The db connection and resolver works fine if I remove the rounds field, so it's something there...
GraphQL supports two kinds of abstract types -- unions and interfaces. An abstract type is a type that represents two or more possible types. Abstract types allow you to specify a single type for your field that could be one of several possible types at runtime (i.e. when the query is executed). When executing a query, GraphQL can never return an abstract type -- instead, the type has to be resolved into one of the possible types when the query is executed.
If a field returns a list, then the type for each item in the list will resolved separately. This type resolution happens before any of the fields on each item are resolved. More to the point, the type that's resolved determines which fields need to be resolved in the first place.
In your example above, you've defined an abstract type (the interface Round) and several possible types for it (LightningRound, MultipleChoiceRound, etc.). However, you have not told GraphQL how to determine whether a Round is a LightningRound, a MultipleChoiceRound or another possible type. This is the purpose of providing a resolveType function. You typically define a resolveType function for each abstract type in your schema. Assuming you're using graphql-tools or apollo-server, you provide this function through the same resolver map object you use to define your resolvers:
const resolvers = {
Round: {
__resolveType: (round) => {
// your code here
},
},
}
resolveType will be passed the Round object (i.e. one of the objects returned by your rounds resolver) -- you can use that value to determine what kind of Round it is. Based on your code, I'm guessing you'd use the type property to differentiate between the different types. resolveType should return a string value with the name of the matched type. So it could be as simple as:
const resolvers = {
Round: {
__resolveType: (round) => {
return round.type
},
},
}
For additional examples, see the docs.
isTypeOf is an alternative approach to resolving the type. Instead of defining a resolveType function for the abstract type, you can define a isTypeOf function for each possible type. This function returns true or false to indicate whether the object it received is in fact the type. There are uses for isTypeOf, but it's typically easier to just use resolveType instead.
I'm trying to learn GraphQL (& node.js & MongoDB etc.). I cant get this simple nested query to return results :
query getLocationByPerson {
People {
firstName
lastName
service {
location
}
}
}
The result I get is :
{
"data": {
"People": [
{
"firstName": "John",
"lastName": "DOE",
"service": null
}
]
},
"errors": [
{
"message": "Cannot return null for non-nullable field Service.location.",
"locations": [
{
"line": 6,
"column": 7
}
],
"path": [
"People",
0,
"service",
"location"
]
}
]
}
All the code is available here : https://github.com/fabricezerrouki/graphql-playground
Can anyone have a look and help me to figure out what I'm doing wrong?
Thanks.
The problem lies in the way you're setting the service attribute when you create and update a person. For nested types, you want to pass an object containing the subtypes. Right now you're passing it just a string, so when you try to set Service equal to args.serviceId in your createPerson resolver, it doesn't exist, and therefore sets the value of that field to null in MongoDB. Re-factor like so:
In index.js
type Mutation {
createPerson(Xid: String!, firstName: String */ ... */ service: { id: ID!, name: String!, location: String! }): People!
}
In /resolvers/Mutation.js
const Mutations = {
createPerson: async (parent, args) => {
const newPerson = new People({
Xid: args.Xid,
firstName: args.firstName
/* and so on... */
Service: args.service.id
});
}
}
Also, you may run into problems in the future given the way your saving the Service object to MongoDB as a Capital "S" Service, whereas your variable in the queries is lowercase "s" service. You'll have to remember any time you search the database to now directly destructure the the args.service into your Model.find({service}) method. Kind of a niche problem, but I've ran into that exact problem myself, so figured I would mention it.
Edited in response to OP comment
Yes it is possible to do an SQL join-link operation to return the Service object with the Person query, but you'll need to to that in the query resolver and just store the Service id during the mutation. In that case I guess the reason it's null is your calling args.serviceId but the createPerson() parameter is simply "service" so try changing Mutation.js to Service: args.service.
As for the actual join operation, that's a bit more complicated. I would recommend first returning the serviceId string to make sure that works correctly. Then you'll need to delve into the MongoDB aggregation pipeline. More specifically, the $lookup pipeline operator performs a function similar to an SQL join. I end up banging my head against the wall every time I have to deal with aggregation pipelines. It's a pretty advanced subject with a confusing syntax IMO. But there are plenty of tutorials and examples out there for doing exactly what your wanting.
I'm trying to populate array of objects using the following code:
inventory.populate(result, {
path: 'activities.mean',
$match: { 'activities.mean': {$ne: ''} }
}, callback);
where type of mean is:
mean:{type:String, ref: 'Inventory'}
While populating a result I get the error in my callback function:
CastError: Cast to ObjectId failed for value "" at path "_id" for model "Inventory"'...
Which clearly shows that I've results that contains empty activities.mean.
I tried different solutions provided including match that I wrote in above code but I can't really make it work. Not sure why match is not working here.
What I'm expecting this code to do is:
if activities.mean is empty string, then do not try to populate that mean.
More looks like that the issue is that you're using String type for a reference field – because of that mongoose is trying to cast string values to ObjectId which is normally used for references. It should be
mean: {
type: Schema.Types.ObjectId,
ref: 'Inventory'
}
Mongoose's documentation itself notes that
Note: ObjectId, Number, String, and Buffer are valid for use as refs. However, you should use ObjectId unless you are an advanced user and have a good reason for doing so.
Sails have support very convenient model througth Waterline, and I have used the 'array' attribute type in the way storing many string, but now I want to store more complex object, Although I can store the raw data in mongo by 'array' type, I don't know if it is safe and I want define the object type in the array, like mongoose's style. for example, I need a model "Products" and I want define it as a 'array' but the object stored in the array only model "Book", what I can do like this, but I don't think it works.
module.exports = {
products : {
type : 'array',
Book : {
name : 'string',
price : 'integer'
}
}
}
So, any suggestion about use of the 'array' and 'json' is very appreciated, thanks so much!
I don't think that the array type is going to work the way you want it to. What you're looking for is associations which will be available in SailsJS 0.10 (which you can get via git right now). The array attribute type for MySQL and PostgreSQL it will only stringify the array and store it as text in the database then it will parse the field when returning the value.
source