AWS AppSync Graphql equivalent of a left join query - left-join

I am trying to join two dynamoDb tables to get a result set similar to a left join. Here is a scaled down version of the tables in question
type MaintenanceRecomendationsMaster
#model
#key(name: "byrecomendID", fields: ["recomendId"], queryField: "byrecomendID") {
id: ID!
recomendId: Int!
displayName: String!
history: [UserMaintenanceHistory]
#connection(keyName: "byRecomendationsMasterId", fields: ["id"])
}
Here is the other table it joins to
type UserMaintenanceHistory
#model
#key(name: "byUserVehicleId", fields: ["uservehicleId"])
#key(name: "byRecomendationsMasterId", fields: ["RecomendationsMasterId"]) {
id: ID!
status: String
actionTakenDate: AWSDateTime
uservehicleId: ID!
RecomendationsMasterId: ID!
maintenanceCache: MaintenanceRecomendationsMaster
#connection(fields: ["RecomendationsMasterId"])
}
This is what the tables looks like with the data
I want to be able to send in recommendId =100 and uservehicleId = 1 to get a response like this
The query I am using like this works but it uses the filter clause which uses a scan operation and has a limitation of only fetching the first 100 records and then applying the filter on those 100 records. I want to run a query where I am currently running a filter right now if possible. I don't want to use custom resolvers if possible, unless that is the only way out.
query byrecomendIdQuery{
byrecomendId(recomendId: 100) {
items {
id
displayName
history (filter: {uservehicleId: {eq: "1"}}) {
items{
status
actionTakenDate
}
}
}
}
}

Related

How to get an array or list as result from a graphql query?

Hello I am new to graphql and I was wondering if it is possible to create a root query in my schema that will return an array or list as a result.
To be more precise I have created the following type in my schema:
const ResourceType = new GraphQLObjectType({
name:'Resource',
fields:()=>({
id: {type: GraphQLID},
url: {type: GraphQLString},
title: {type: GraphQLString},
author: {type: GraphQLString},
license:{type: GraphQLString},
LicenseScore: {type: GraphQLFloat},
})
});
And I want to query all the resources in my database so that I get their license type and then assign a score according to the license. Is it possible to have a query that gets the license for each resource and returns an array like this: [[id:1209,score:3.5],[1203,4.5]....]?
I have created a mutation that updates the score to the database, here it is:
updateAllLicenses: {
type: new GraphQLList(ResourceType),
async resolve(parent,args){
var licns;
var scr;
await Resource.find({}).then(async function(results){
var num = results.length;
var scr=0;
for (var i=0; i<num; i++){
if (! (results[i].license in licenseScores)){
scr = 0;
}
else{
scr = licenseScores[results[i].license];
}
await Resource.findByIdAndUpdate(results[i].id{LicenseScore:scr});
}
});
return await Resource.find({});
}
}
However I was wondering if there is a way to get these scores directly from the query instead of saving them in the database. I tried changing the type to new GraphQLList(GraphQLFloat) and returning an array with the scr values but I get an error in the graphql api saying I have the wrong output type in my mutation.
From your schema, it seems to me that you are able to fetch results, as an array of objects, with an output like this:
[
{
id: 1,
license: "value1"
},
{
id: 2,
license: "value2"
}
]
If this is all you need, then the approximate query should work:
query Resource {
id
url
license
licenseScore
}
Once you have your array of objects, you can convert it to an array of arrays, although I would not advise that.
Since you are just getting started in GraphQL, I recommened these resources:
HowToGraphql: clean videos/posts on GraphQL
Apollo Graphql's documentation and blogs. Here is one of the posts on queries
Also, if you want to test your queries and get accustomed to them, use GraphQL Playground

How to write JOIN in graphQL or get result from multiple types - AWS App sync iOS

I am using AWS AppSync for a chat app in one of the my applications. We are able to do setup and basic query successfully.
In one of the case I need to write a customized GraphQL query so that I can have additional data using reference of one type from another. For example, I can have allMessageGroup from a user and also allMessages from a particular group.
Now I want to add the last message in the group and its sender with the list of all message group just like what's app home page.
But I am not able to understand how make JOIN or write such query which give mixed results based on Conversation/Message/User types/table.
Platform:iOS
Language: Swift
For detail below is my Schema and API/Query I am using
Schema
type Conversation {
conversation_cover_pic: String
conversation_type: String!
createdAt: String
id: ID!
messages(after: String, first: Int): MessageConnection
name: String!
privacy: String
}
type Message {
author: User
content: String!
conversationId: ID!
createdAt: String
id: ID!
recipient: User
sender: String
}
type MessageConnection {
messages: [Message]
nextToken: String
}
Query
query getUserConversationConnectionThroughUser($after: String, $first: Int)
{
me
{
id
__typename
conversations(first: $first, after: $after)
{
__typename
nextToken
userConversations
{
__typename
userId
conversationId
associated
{
__typename
userId
}
conversation
{
__typename
id
name
privacy
messages
{
__typename
id
conversationId
content
createdAt
sender
isSent
}
}
}
}
}
}
It sounds like you need multiple requests to one or more datasources to fulfill this graphQL query. In this case, you can use AppSync's pipeline resolver feature.
With pipeline resolvers, you can create multiple functions, each of which can use the results of the previous function and query a database. These functions run in an order you specify.
An example of something you could do with a pipeline resolver:
One function will query the chat group database
A second function will use the results of the chat group to fetch messages
Consolidate all the results into one graphQL response containing group information and messages
Here is the documentation for pipeline resolvers: https://docs.aws.amazon.com/appsync/latest/devguide/pipeline-resolvers.html

Appsync Fine Graine Control on Mutation with Multiple Tables

I have the following schema where the author of an Event can make notes on the Event. Only the author of the event should be able to create notes. I store the author in the Event. However, I'm finding other users are able to create a note on an event they didn't author by simply passing the eventId of an another users event, like so:
mutation {
noteOnEvent(input: { eventId: "***", content: "A comment"}) {
eventId
content
}
}
How can i prevent this? I don't see a way to access the EventTable author to in the noteOnEvent resolver
Schema
type Note {
eventId: ID!
notetId: ID!
content: String
author: String
}
input CreateNoteInput {
eventId: ID!
noteId: String!
content: String
}
type Event {
id: ID!
name: String
author: String
notes: [Note]
}
You can accomplish this using a Nested Resolver.
If you modify your schema slightly, you can accomplish it like so:
type EventCheckedNote {
// Add a resolver on note which creates the note. The event will be available as $cxt.source, and you can make an authZ check before making the mutation.
note: Note
}
type Mutation {
// Add a resolver on noteOnEvent which queries the Event table.
noteOnEvent(input: CreateNoteInput!): EventCheckedNote
}
Here is a tutorial on using nested resolvers to perform authorization checks with multiple data sources involved: https://hackernoon.com/graphql-authorization-with-multiple-data-sources-using-aws-appsync-dfae2e350bf2

Mongoose product category design?

I would like to create an eCommerce type of database where I have products and categories for the products using Mongodb and Mongoose. I am thinking of having two collections, one for products and one for categories. After digging online, I think the category should be as such:
var categorySchema = {
_id: { type: String },
parent: {
type: String,
ref: 'Category'
},
ancestors: [{
type: String,
ref: 'Category'
}]
};
I would like to be able to find all the products by category. For example "find all phones." However, the categories may be renamed, updated, etc. What is the best way to implement the product collection? In SQL, a product would contain a foreign key to a category.
A code sample of inserting and finding a document would be much appreciated!
Why not keep it simple and do something like the following?
var product_Schema = {
phones:[{
price:Number,
Name:String,
}],
TV:[{
price:Number,
Name:String
}]
};
Then using projections you could easily return the products for a given key. For example:
db.collection.find({},{TV:1,_id:0},function(err,data){
if (!err) {console.log(data)}
})
Of course the correct schema design will be dependent on how you plan on querying/inserting/updating data, but with mongo keeping things simple usually pays off.

Performance on sorting by populated field using mongoose

I have learned that it is not possible to sort by populated field in mongodb during querying. Suppose I have a schema like below, and I have 1 million data in record. And i only need to return 10 records for each query, depending of the column sorting (asc/desc) and page defined. What are the effective solution to this problem?
Simplify problem:
In the front end, I will have a data table with column firstname, lastname, test.columnA and test.columnB. Each of this column is sortable by user.
My initial solution was to query everything out in mongoose, flattening it to json and using javascript to reorder and finally response the final 10 data only. But this will have bad performance impact with increasing data set.
var testSchema = {
columnA: { type: String },
columnB: { type: String },
}
var UserSchema = {
firstname: { type: string },
lastname: { type: string },
test: {
type: ObjectId,
ref: 'Test'
}
}