Unable to query Many to Many relationship in Amplify Datastore - javascript

I have 2 model with Many-to-Many Relationship. The 2 model is Order and Product. An Order will have many Product and Product will in many Order.
My Goal is : Given a orderID, get a list of productID in the Order
So I followed this Amplify guide to group the into OrderProducts , Order and Product like this schema.graphql
type Order #model #key(name: "byStore", fields: ["storeID"]) #auth(rules: [{allow: private, operations: [read, update, create, delete]}]) {
id: ID!
buyer_name: String
order_total_amount: String
products: [OrderProducts] #connection(keyName: "byOrder", fields: ["id"])
created_at: AWSTimestamp
}
type OrderProducts #model #key(name: "byOrder", fields:["orderID", "productID"]) #key(name: "byProduct", fields:["productID", "orderID"]) #auth(rules: [{allow: private, operations: [read, update, create, delete]}]){
id: ID!
orderID: ID!
productID: ID!
order: Order! #connection(fields: ["orderID"])
product: Product! #connection(fields: ["productID"])
}
type Product #model #key(name: "byStore", fields: ["storeID"]) #auth(rules: [{allow: owner, operations: [create, update, delete]}, {allow: public, provider: iam, operations: [read]}]){
id: ID!
product_name: String!
product_price: String!
created_at: AWSTimestamp
orders: [OrderProducts] #connection(keyName: "byProduct", fields:["id"])
}
But when I query the OrderProduct model like below, in order to get a List of Products by OrderID:
import { Product, OrderProducts } from '../models';
export const GetAllProductIdByOrderId = async (order) => {
return await DataStore.query(OrderProducts, op => op.orderID("eq", order.id)) // this is actual orderID
}
I get this error as a result:
Error: Invalid field for model. field: orderID, model: OrderProducts
What I tried:
Attempt 1
I tried to add a queryField named getOrderByOrderIDByProductID in OrderProducts like this:
type OrderProducts #model #key(name: "byOrder", fields:["orderID", "productID"], queryField: "getOrderByOrderIDByProductID") #key(name: "byProduct", fields:["productID", "orderID"]) #auth(rules: [{allow: private, operations: [read, update, create, delete]}]){
id: ID!
orderID: ID!
productID: ID!
order: Order! #connection(fields: ["orderID"])
product: Product! #connection(fields: ["productID"])
}
Then amplify push, amplify codegen models, after all this, I cant import getOrderByOrderIDByProductID in my file and get this error
warn Attempted import error: 'getOrderByOrderIDByProductID' is not exported from '../models' (imported as 'getOrderByOrderIDByProductID').
So I checked my model/index.js , it dont have getOrderByOrderIDByProductID exported. So dont know what else I can do.
Attempt 2
I go to AppSync console, I seen getOrderByOrderIDByProductID in my query section, then I tried to run this query:
query MyQuery {
getOrderByOrderIDByProductID(filter: {orderID: {eq: "8649a9da-9ea6-4a30-afe7-6b336a8f853d"}}) {
items {
order {
buyer_name
createdAt
id
}
}
}
}
Then I get the following output:
{
"data": {
"getOrderByOrderIDByProductID": null
},
"errors": [
{
"path": [
"getOrderByOrderIDByProductID"
],
"data": null,
"errorType": "MappingTemplate",
"errorInfo": null,
"locations": [
{
"line": 2,
"column": 3,
"sourceName": null
}
],
"message": "Expression block '$[query]' requires an expression"
}
]
}
I cant get any productID from the query and dont know what is the result mean.
I followed the suggestion mention in this github issue and reported in github as well, if you wanna to read a more detail version can read it here.
To summarize:
Only 1 goal: Given an orderID, give me a list of productID inside the Order.
And tell me what I doing wrong, if possible, give me an example. Cause I followed this example in amplify docs and still having this issue

Related

Correct way to work with a many-to-many relationship in Amplify. Unable to make mutation

I have modelled a many-to-many relationship in Amplify between Product and Order. However, I cannot pass a productID when creating an Order. I get the error :
The variables input contains a field name 'products' that is not defined for input object type 'CreateOrderInput'
Product Model
type Product #model #auth(rules: [{allow: public}]) {
id: ID!
name: String
price: Int
Orders: [Order] #manyToMany(relationName: "ProductOrder")
}
Order Model
type Order #model #auth(rules: [{allow: public}]) {
id: ID!
totalprice: Int
products: [Product] #manyToMany(relationName: "ProductOrder")
}
As per documentation, amplify creates a join table "ProductOrder" in dynamodb.
createProduct according to Amplify
Amplify tells me that I can create a product with:
const newProduct = await API.graphql({
query: createProduct,
variables: {
input: {
"name": "Lorem ipsum dolor sit amet",
"price": 1020,
"Orders": [],
}
}
});
As I don't have any orders yet, I create a product without linking it to an order. All working fine.
createOrder according to Amplify
const newOrder = await API.graphql({
query: createOrder,
variables: {
input: {
"totalprice": 1020,
"products": [],
}
}
});
When I want to create an order (and already have a product), I'm getting an error message.
The variables input contains a field name 'products' that is not defined for input object type 'CreateOrderInput'
I analyze 'CreateOrderInput' and indeed it looks like this:
input CreateOrderInput {
id: ID
totalprice: Int!
}
So, basically what is the correct way of creating a new Order and passing a productID with it? Do I have to create the Order and then manually call createProductOrder and manually create a record in the join table (ProductOrder) ?

Query multiple fields with same value [GraphQL][Amplify]

I'm creating an API with AWS Amplify and AppSync GraphQL. I Work on a Tinder like App.
I would like to search the same value in two fields for a Query. I've tried a lot of solutions, but none seems to work.
I have a User #Model which is connected to many Match via #connection
type User #model
#auth(rules: [{allow: public}])
{
id: ID!
email: String!
password: String
age: String!
name: String!
description: String
pickupLine: String
orientation: Orientation!
gender: Gender!
animal: Animal!
profilePicture: String!
pictures: [String]!
location: Location
numberOfSparksAvailable: Int!
matchs: [Match]
#connection(keyName: "byUser", fields: ["id"])
sparks: [Spark]
#connection(keyName: "byUser", fields: ["id"])
}
And I have a Match #Model which have a senderId field and a receiverId field
type Match #model
#auth(rules: [{allow: public}])
#key(name: "byUser", fields: ["receiverId", "senderId"], queryField: "matchByUser")
#key(name: "bySender", fields: ["senderId"], queryField: "sparkBySender")
#key(name: "byReceiver", fields: ["receiverId"], queryField: "sparkByReceiver")
{
id: ID!
status: MatchStatus!
matchType: MatchType
sender: User! #connection(fields: ["senderId"])
senderId: ID!
receiver: User! #connection(fields: ["receiverId"])
receiverId: ID!
answerFrom: Answer!
answerTo: Answer
chatRoomId: ID!
chatRoom: ChatRoom!
#connection(fields: ["chatRoomId"])
deletedAt: AWSDate
}
And and I don't find any way to make bySender #key look for both senderId and receiverId. I want to be able to have all the Matches for a User whether he's the receiver or the sender.
But when I make a Query to ListUsers I only get the Matches where the User is a receiver.
I've also tried to make multiple #connection but it is not allowed by Graphql-transformer.
I also tried to make an usersId: [ID!]! like that
type Match #model {
...
usersId: [ID!]!
users: [User!]!
#connection(fields: ["usersId"])
...
}
But It's also not allowed by graphql-transformer..
Has anyone a solution to get all the matches for a User?
Thanks a lot !

Apollo client and graphQl query error : Variable '$where' expected value of type 'OrganizationWhereUniqueInput

Hi I'm making a backend server with GraphQL, Apollo client & Prisma. I'm trying to write a query where I get organization data back. The user who sends the query should get its organization data back based on their id. When running the query in playground I get this error.
error:
"message": "Variable '$where' expected value of type 'OrganizationWhereUniqueInput!' but got: {\"employees\":{\"id\":\"ckas83z13t9qk0992pucglc4k\"}}. Reason: 'employees' Field 'employees' is not defined in the input type 'OrganizationWhereUniqueInput'. (line 1, column 8):\nquery ($where: OrganizationWhereUniqueInput!) {\n ^",
I don't see what I did wrong. I'm still pretty new to it all. I tried to write the function in Query.js in different ways but no luck. Also, I still find the error messages you get in playground very confusing
schema:
type Query {
getOrganization: Organization!
}
type Organization {
id: ID!
name: String!
country: String!
street: String!
zipCode: Int!
houseNumber: Int!
addings: String
employees: [User!]
}
type User {
id: ID!
firstname:String!
lastname:String!
email: String!
services: [Service!]
organization: Organization!
}
query.js
function getOrganization(parent, args, context, info){
const userId = getUserId(context)
return context.prisma.organization({employees:{id:userId}})
}
// also tried this
/*
function getOrganization(parent, args, context, info){
const userId = getUserId(context)
return context.prisma.organization({where: {employees:{id:userId}}})
}*/
User.js
function services (parent, args, context){
return context.prisma.user({id: parent.id}).services()
}
function organization (parent, args, context){
return context.prisma.user({id: parent.id}).organization()
}
module.exports={
services,
organization
}
Organization.js
function employees(parent, args, context){
return context.prisma.organization({id: parent.id}).employees()
}
module.exports={
employees
}
Could anyone help me see what went wrong?
query in playground:
query{
getOrganization{
name
id
}}
HTTP HEADER:
{
"Authorization": "Bearer {contains user token }"
}
Just use OrganizationWhereInput instead of OrganizationWhereUniqueInput. It will return a list of organisations instead of a single result (might return an empty array), yet it should allow you to search for an organisation using an employee id.

GraphQL throwing syntax errors

I am developing the GraphQL Node tutorial, and am up to step 7.
https://www.howtographql.com/graphql-js/7-subscriptions/
I am getting a number of syntax errors from this code in my datamodel.prisma file:
directive #id on FIELD_DEFINITION
directive #unique on FIELD_DEFINITION
directive #createdAt on FIELD_DEFINITION
scalar DateTime
type Link {
id: ID! #id
createdAt: DateTime! #createdAt
description: String!
url: String!
postedBy: User
votes: [Vote!]!
}
type User {
id: ID! #id
name: String!
email: String! #unique
password: String!
links: [Link!]!
votes: [Vote!]!
}
type Vote {
id: ID! #id
link: Link!
user: User!
}
But am still getting 'User' type [#6:1] tried to redefine existing 'User' type [#15:5] and 'Link' type [#24:1] tried to redefine existing 'Link' type [#6:5].
I am also not sure if I am declaring directives or scalars correctly as this is missing from the official tutorial.
Can anyone give any advice on how to sort these issues?
Schema.graphql:
type Query {
info: String!
feed(filter: String, skip: Int, first: Int, orderBy: LinkOrderByInput): Feed!
}
type Feed {
links: [Link!]!
count: Int!
}
type AuthPayload {
token: String
user: User
}
type User {
id: ID!
name: String!
email: String!
links: [Link!]!
}
type Vote {
id: ID!
link: Link!
user: User!
}
type Link {
id: ID!
description: String!
url: String!
postedBy: User
votes: [Vote!]!
}
type Subscription {
newLink: Link
newVote: Vote
}
type Mutation {
post(url: String!, description: String!): Link!
signup(email: String!, password: String!, name: String!): AuthPayload
login(email: String!, password: String!): AuthPayload
vote(linkId: ID!): Vote
}
enum LinkOrderByInput {
description_ASC
description_DESC
url_ASC
url_DESC
createdAt_ASC
createdAt_DESC
}
I had the same error this morning and I have a feeling it has something to do with caching. It went away when I renamed the variable. In your case, change all 'Link' definition/references to 'LinkTwo' and see if the error goes away. Same with 'User'... change it to 'UserTwo'. If it does, perhaps you can rename them back afterwards.
I haven't used Prisma before and only glanced at the tutorial but it looks like you're defining two User types; you have one in datamodel.prisma and Schema.graphql (I couldn't find two definitions of User in the tutorial). If they are read into the same instance, that'll be the reason why graphql thinks you are trying to redefine the User type. Remove one or, if it's applicable, change the second to extend type User should solve the syntax error.

GraphQL how to do a JOIN request instead of many sequential request?

I have two GraphQL type:
type Author {
id: String!
name: String!
}
type Book {
id: String!
author: Author!
name: String!
}
In my database, it is implemented by a foreign key inside the books table:
table authors (pseudo code)
`id` INTEGER UNSIGNED
`name` STRING
table books (pseudo code)
`id` INTEGER UNSIGNED
`author_id` INTEGER UNSIGNED REFERENCE `authors.id`
`name` STRING
So when I resolve a GraphQL query like:
query allTheBooks {
id
name
author {
id
name
}
}
I would like to do only one SELECT SQL query like:
SELECT books.id, books.name, authors.id, authors.name
FROM books
LEFT JOIN authors ON authors.id = books.author_id
Instead of the current:
SELECT books.id, books.name, books.author_id
FROM books
SELECT authors.id, authors.name
FROM authors
WHERE author.id = [one the the books.author_id of the first SELECT]
SELECT authors.id, authors.name
FROM authors
WHERE author.id = [one the the books.author_id of the first SELECT]
[...]
Is there a way to know which "child fields" are queried in a GraphQL resolver ?
Thank you in advance for your answer !
I just discovered that in the fourth parameter gived at the resolver, there where an array of the queried fields: info.fieldNodes[0].selectionSet.selections.
I didn't found any documentation about this, and I wonder what represent the fieldNodes array... (and dont like to access the first element that way without knowing it...).
The selections object contains an array like this:
[
{
kind: 'Field',
alias: undefined,
name: { kind: 'Name', value: 'id', loc: [Object] },
arguments: [],
directives: [],
selectionSet: undefined,
loc: { start: 36, end: 38 }
},
{
[...]
},
...
]
Here, the value: 'id' match the name of the queried field of the related author.
If I go a level deeped, the selectionSet: undefined becomes an object and the pattern repeat itself recursively...

Categories