I cannot mutate a list of objects completely, because only the last element of the array will be mutated.
What already works perfectly is, if I put each element ({play_positions_id: ...}) in the array manually like here:
mutation CreateProfile {
__typename
create_profiles_item(data: {status: "draft", play_positions: [{play_positions_id: {id: "1"}}, {play_positions_id: {id: "2"}}]}) {
id
status
play_positions {
play_positions_id {
abbreviation
name
}
}
}
}
Output:
{
"data": {
"__typename": "Mutation",
"create_profiles_item": {
"id": "1337",
"status": "draft",
"play_positions": [
{
"play_positions_id": {
"id": "1",
"abbreviation": "RWB",
"name": "Right Wingback"
}
},
{
"play_positions_id": {
"id": "2",
"abbreviation": "CAM",
"name": "Central Attacking Midfielder"
}
}
],
}
}
}
Since you can add many of those elements, I defined a variable/argument like here
mutation CreateProfile2($cpppi: [create_profiles_play_positions_input]) {
__typename
create_profiles_item(data: {status: "draft", play_positions: $cpppi}) {
id
status
play_positions {
play_positions_id {
id
abbreviation
name
}
}
}
}
Variable object for above:
"cpppi": {
"play_positions_id": {
"id": "1"
},
"play_positions_id": {
"id": "2
}
}
Output:
{
"data": {
"__typename": "Mutation",
"create_profiles_item": {
"id": "1338",
"play_positions": [
{
"play_positions_id": {
"id": "2",
"abbreviation": "CAM",
"name": "Central Attacking Midfielder"
}
}
],
}
}
}
Schema:
input create_profiles_input {
id: ID
status: String!
play_positions: [create_profiles_play_positions_input]
}
input create_profiles_play_positions_input {
id: ID
play_positions_id: create_play_positions_input
}
input create_play_positions_input {
id: ID
abbreviation: String
name: String
}
At the last both snippets, only the last object with the id "2" will be mutated. I need these to use the defined input type from my backend.
I figured it out. I got it wrong with the brackets in the variable. Here the solution:
"cpppi": [
{
"play_positions_id": {
"id": "1"
}
},
{
"play_positions_id": {
"id": "2"
}
}
]
What I want to do
Add data using DQL mutation https://github.com/dgraph-io/dgo#running-a-mutation and these data to also be visible via graphql.
Dgraph version: v21.03.2
DQL schema:
<Product.created_at>: datetime .
<Product.image>: string .
<Product.name>: string #index(hash) #upsert .
<Product.slug>: string #index(hash) #upsert .
<Product.updated_at>: datetime .
<dgraph.drop.op>: string .
<dgraph.graphql.p_query>: string #index(sha256) .
<dgraph.graphql.schema>: string .
<dgraph.graphql.xid>: string #index(exact) #upsert .
type <Product> {
Product.name
Product.slug
Product.image
Product.created_at
Product.updated_at
}
type <dgraph.graphql> {
dgraph.graphql.schema
dgraph.graphql.xid
}
type <dgraph.graphql.persisted_query> {
dgraph.graphql.p_query
}
GraphQL schema:
type Product {
id: ID!
name: String! #id #dgraph(pred: "Product.name")
slug: String! #id #dgraph(pred: "Product.slug")
image: String #dgraph(pred: "Product.image")
created_at: DateTime! #dgraph(pred: "Product.created_at")
updated_at: DateTime! #dgraph(pred: "Product.updated_at")
}
Using the above schema, graphql queries are working fine.
Graphql mutation
mutation MyMutation {
addProduct(input: {name: "product 1", slug: "prod-1", created_at: "2021-10-04T06:37:57.707227339Z", updated_at: "2021-10-04T06:37:57.707227339Z"}) {
numUids
}
}
Graphql Query
query MyQuery {
queryProduct {
name
}
}
response of the graphql query:
{
"data": {
"queryProduct": [
{
"name": "product 1"
}
]
},
"extensions": {
"touched_uids": 2,
"tracing": {
"version": 1,
"startTime": "2021-10-04T06:42:01.064395081Z",
"endTime": "2021-10-04T06:42:01.065675778Z",
"duration": 1280687,
"execution": {
"resolvers": [
{
"path": [
"queryProduct"
],
"parentType": "Query",
"fieldName": "queryProduct",
"returnType": "[Product]",
"startOffset": 110469,
"duration": 1164739,
"dgraph": [
{
"label": "query",
"startOffset": 149859,
"duration": 1123999
}
]
}
]
}
}
}
}
Then I did a mutation using dgo: https://github.com/dgraph-io/dgo#running-a-mutation and the data are shown fine using the ratel tool.
When I try again the Graphql Query:
query MyQuery {
queryProduct {
name
}
}
none of these are returned in the graphql response.
The issue is because the dgraph also wants a DType to be passed via dql mutation like so:
models.Product{
Name: "product name",
Slug: "product-slug",
Image: "test.jpg",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
DType: []string{"Product"}, // here is the trick
}
I have this query:
getMyTransactions {
id
createdAt
}
And I got this error:
"message": "Cannot return null for non-nullable field Transaction.createdAt.",
"path": [
"_entities",
0,
"createdAt"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"serviceName": "XXX",
"query": "query($representations:[_Any!]!){_entities(representations:$representations){...on Transaction{createdAt}}}",
"variables": {
"representations": [
{
"__typename": "Transaction",
"id": "29bf75e5-b79e-4a7d-a021-84a8b5662aa8"
},
{
"__typename": "Transaction",
"id": "616f3f8a-3c81-4d2e-bce0-03d031a15062"
}
]
},
//etc
Why isvariables.representations missing createdAt values? When I do a query directly to DynamoDB I can see createdAt values for all those 2 items.
My schemas are like this:
extend type Transaction #key(fields: "id") {
id: ID! #external
}
type Query {
getMyTransactions: [Transaction!]!
}
And the other schema has Transaction type:
type Transaction #key(fields: "id") {
id: ID!
createdAt: String!
}
I have an AppSync graphql schema with Users and Events, that should have a bi-directional connection. My schema looks like this:
type User #model {
id: ID!
email: String
events: [EventUser] #connection(name: "EventUser", keyName: "byUser", fields: ["id"])
}
type Event #model {
id: ID!
name: String
description: String
registeredUsers: [EventUser] #connection(name: "EventUser", keyName: "byEvent", fields: ["id"])
invitedUsers: [User]
}
type EventUser
#model(queries: null)
#key(name: "byEvent", fields: ["eventId", "userId"])
#key(name: "byUser", fields: ["userId", "eventId"]) {
id: ID!
eventId: ID!
userId: ID!
event: Event! #connection(fields: ["eventId"])
user: User! #connection(fields: ["userId"])
}
The query that is generated by the CLI looks like this:
export const listEvents = /* GraphQL */ `
query ListEvents(
$filter: ModelEventFilterInput
$limit: Int
$nextToken: String
) {
listEvents(filter: $filter, limit: $limit, nextToken: $nextToken) {
items {
id
name
description
registeredUsers {
nextToken
}
createdAt
updatedAt
}
nextToken
}
}
`;
When I run this query with:
const result = await API.graphql(graphqlOperation(queries.listEvents, { limit: 10}))
I get these results:
[
{
"createdAt": "2020-08-17T21:36:04.502Z",
"description": "Event description",
"id": "some-unique-id",
"name": "Event name",
"registeredUsers": Object {
"nextToken": null,
},
"updatedAt": "2020-08-17T21:36:04.502Z",
},
{
"createdAt": "2020-08-17T21:36:04.502Z",
"id": "some-other-unique-id",
"name": "event 2 name",
"registeredUsers": Object {
"nextToken": null, // <- This seems wrong.
},
"updatedAt": "2020-08-17T21:36:04.502Z"
}
]
The registeredUsers field should be an array of items. I can run a query in the AppSync console like this:
query ListEvents {
listEvents( limit: 10) {
items {
id
name
registeredUsers {
items {
userId
}
}
}
}
}
and it returns correct results:
{
"data": {
"listEvents": {
"items": [
{
"id": "some-unique-id",
"name": "event name",
"registeredUsers": {
"items": [
{
"userId": "user"
},
{
"userId": "user1"
}
]
}
},
{
"id": "some-other-unique-id",
"name": "event 2 name",
"registeredUsers": {
"items": []
}
},
]
}
}
}
Obviously, the console query is slightly different but it produces correct results, although it does not handle nextToken pagination.
My question is this: Is the CLI-generated query invalid? If so, is it because my Schema is not set up correctly?
If the generated query is valid, how would I call it to get the EventUser data?
I'm new to all graphql world, so this might be a very easy question, sorry
I'm using graphql-compose-mongoose to generate my graphql schema, here's my mongoose schema:
const ComplainSchema = new Schema({
entityId: {type: String, required: true},
user: {type: UserInfoSchema, required: true},
title: String, // standard types
desc: String,
state: {required: true, type: String, enum: ["DRAFT", "MODERATION", "PUBLIC", "SOLVED"]},
attachments: [{
url: {type: String, required: true},
name: String,
mimeType: String,
attachmentId: Schema.Types.ObjectId
}],
createdAt: {type: Date, index: true},
updatedAt: {type: Date, index: true},
}, {timestamps: {}})
export default mongoose.model('Complaint', ComplainSchema)
If I attempt the following mutation in graphiql it works fine
mutation {
complaintUpdateById(record:{_id:"5bdd9350fe144227042e6a20", title:"ok", desc:"updated", attachments:[{name:"zied", url:"http://zied.com"}]}){
recordId,
record{
_id,
entityId,
user {
userId,
userName,
roleInShop
},
title,
desc,
createdAt,
updatedAt,
attachments{
name,
url
}
}
}
}
and returns this (in case there could be helpful to see the response)
{
"data": {
"complaintUpdateById": {
"recordId": "5bdd9350fe144227042e6a20",
"record": {
"_id": "5bdd9350fe144227042e6a20",
"entityId": "5bd9b1858788f51f44ab678a",
"user": {
"userId": "5bd9ac078788f51f44ab6785",
"userName": "Zied Hamdi",
"roleInShop": "ASA"
},
"title": "ok",
"desc": "updated",
"createdAt": "2018-11-03T12:23:44.565Z",
"updatedAt": "2018-11-05T09:02:51.494Z",
"attachments": [
{
"name": "zied",
"url": "http://zied.com"
}
]
}
}
}
}
Now if I try to pass the attachments to apollo, I don't know how to do that, I don't know which type to provide (Attachment is not the right type obvisouly):
const UPDATE_COMPLAINT = gql `mutation complaintUpdateById($_id:MongoID!, $title: String!, $desc: String!, $attachments: [Attachment]
)
{
complaintUpdateById(record:{_id:$_id, title:$title, desc:$desc, attachments:$attachments}){
recordId,
record{
_id,
entityId,
user {
userId,
userName,
roleInShop
},
title,
desc,
createdAt,
updatedAt
}
}
}`
So searching for the right type, I did a introspection of my object, the issue is that I get the type of attachment as null for this query:
{
__type(name: "Complaint") {
kind
name
fields {
name
description
type {
name
}
}
}
}
this is the response:
{
"data": {
"__type": {
"kind": "OBJECT",
"name": "Complaint",
"fields": [
{
"name": "entityId",
"description": null,
"type": {
"name": "String"
}
},
{
"name": "user",
"description": null,
"type": {
"name": "ComplaintUser"
}
},
{
"name": "title",
"description": null,
"type": {
"name": "String"
}
},
{
"name": "desc",
"description": null,
"type": {
"name": "String"
}
},
{
"name": "state",
"description": null,
"type": {
"name": "EnumComplaintState"
}
},
{
"name": "attachments",
"description": null,
"type": {
"name": null
}
},
{
"name": "createdAt",
"description": null,
"type": {
"name": "Date"
}
},
{
"name": "updatedAt",
"description": null,
"type": {
"name": "Date"
}
},
{
"name": "_id",
"description": null,
"type": {
"name": null
}
}
]
}
}
}
googling didn't help since I don't know how is this operation called, I don't think it's a nested mutation from what I found...
Ok fixed,
I did these steps:
I first introspected the type of attachment in a regular query using the __typename keyword: as follows
mutation {
complaintUpdateById(record:{_id:"5bdd9350fe144227042e6a20", title:"ok", desc:"updated", attachments:[{name:"zied", url:"http://zied.com"}]}){
recordId,
record{
_id,
entityId,
user {
userId,
userName,
roleInShop
},
title,
desc,
createdAt,
updatedAt,
attachments{
__typename,
name,
url
}
}
}
}
it showed up a type named ComplaintAttachments
when replacing the Attachment type with this new value, ComplaintAttachments, an error occured and that error message helped me out:
Variable "$attachments" of type "[ComplaintAttachments]" used in
position expecting type "[ComplaintComplaintAttachmentsInput]"
so the array is of type ComplaintComplaintAttachmentsInput, I still don't know how to introspect it directly, but I'm already happy with the result :)