In this post, we'll try to understand how to search/filter and result work in AWS Amplify and AppSync.
Prerequisites:
1/ GraphQL Learn
2/ Data modeling
If you don't know about data modeling check out my previous blog about data-modeling
If you've no idea about any prerequisites, I recommend learning them highly.
Directives
@modal @auth @hasOne @hasMany @manyToMany @searchable @primaryKey @index
@searchable
- Needs to setup ElasticSearch (We'll not do this in this post)
- Active search and sorting at the same time.
other directives
- I've briefly described other directives in the data-modeling blog. If you don't know about other directives click here to learn.
Data Types
- Scalar type: id, name, date_of_birth, got_job, gpa etc. (which has scalar value like ID, String, Float, Int, Boolean, AWSDate etc.)
- Object type: Status, Student ( which is a javascript object)
Supported Search Operations
Data Type | Supported operations |
---|---|
String | ne, eq, match, matchPhrase, matchPhrasePrefix, multiMatch, exists, wildcard, regexp |
Int | ne, gt, lt, gte, lte, eq, range |
Float | ne, gt, lt, gte, lte, eq, range |
Boolean | ne, eq |
Enum | ne, eq, match, matchPhrase, matchPhrasePrefix, multiMatch, exists, wildcard, regexp |
Object | not supported |
ne (not equal), eq (equal), gt (greater than), lt (lesser than), gte (greater than or equal), lte (lesser than or equal)
Without @searchable
directive
We can do filter with or without @searchable
directive.We'll get filter argument for every list resolvers like (listStudents, listStatuses etc.)
Go to the DOCS or Documentation Explorer, and now search for the list resolver name you want to apply the filter. Click on any list resolver you want to apply filter. Here we're clicking on the liststudents resolver to apply the filter.
Inside listStudents we get the filter argument. Click on the filter argument to see what conditions we can apply to filter out data.
Inside filter argument, we can see multiple fields that can use to filter out data. If we pay attention to argument fields, we see that all the filter options are available only for the scalar field. No object fields are available like status
Dummy data for testing:
We've created some data to test filtering. If you don't know how to add a document/data in database or how hasOne, hasMany, manyToMany relation works, I suggest you to check out the data-modeling blog. Now we'll apply filter on this below data
{
"data": {
"listStudents": {
"items": [
{
"id": "9f928a7a-f096-4ad8-b0cc-5b354dde6b18",
"name": "Raisa",
"email": "raisa@gmail.com",
"gpa": 3.7,
"got_job": true,
"statusID": "b3a4a939-50ed-4d3c-a21e-8048834391f5",
"status": {
"is_enrolled": true,
"is_passed": false
},
"date_of_birth": "1998-07-17",
"exam_completed": 2
},
{
"id": "31092e63-e421-4bbc-afe8-f2092e309442",
"name": "Ashim",
"email": "ashim@gmail.com",
"gpa": 3.2,
"got_job": false,
"statusID": "2cc614a4-0bd1-4a8d-80a8-bc0c8372788b",
"status": {
"is_enrolled": false,
"is_passed": true
},
"date_of_birth": "1998-04-15",
"exam_completed": 3
},
{
"id": "9a3a92df-e4be-4258-ae02-502e0bfd3745",
"name": "Hasan",
"email": "hasan@gmail.com",
"gpa": 3.4,
"got_job": false,
"statusID": "840a91da-75ce-4cd5-8a41-58081763a933",
"status": {
"is_enrolled": true,
"is_passed": false
},
"date_of_birth": "1998-03-22",
"exam_completed": 1
},
{
"id": "ff173ed6-5749-4a54-903b-025675f828e5",
"name": "Minhaj",
"email": "minhaj@gmail.com",
"gpa": 3.7,
"got_job": true,
"statusID": "e1f9ccc1-132f-443a-9f37-821ed634cfc1",
"status": {
"is_enrolled": true,
"is_passed": false
},
"date_of_birth": "1998-04-21",
"exam_completed": 3
},
{
"id": "bc70feab-da91-4ba5-a626-ee99c9f4c4a0",
"name": "Totul",
"email": "totul@gmail.com",
"gpa": 3.4,
"got_job": false,
"statusID": "ca9064ff-5c2f-4634-8dca-d12f10acd1db",
"status": {
"is_enrolled": false,
"is_passed": true
},
"date_of_birth": "1998-03-29",
"exam_completed": 1
},
{
"id": "514b1115-7c95-4037-884f-4d5eae58dc4b",
"name": "Mahadhi",
"email": "mahadhi@gmail.com",
"gpa": 3.6,
"got_job": true,
"statusID": "ec2d4c20-4022-4084-9d52-19ec2cd18503",
"status": {
"is_enrolled": false,
"is_passed": true
},
"date_of_birth": "1993-07-21",
"exam_completed": 4
},
{
"id": "7054f363-3f3c-4343-9dff-f7e4491a797f",
"name": "Shuvo",
"email": "shuvo@gmail.com",
"gpa": 2.5,
"got_job": false,
"statusID": "1958dea4-59b4-4766-b725-476747b8b4c3",
"status": {
"is_enrolled": false,
"is_passed": true
},
"date_of_birth": "1998-02-15",
"exam_completed": 2
},
{
"id": "bf74457b-a1e4-4715-880f-1425bedaaa09",
"name": "Ayesha",
"email": "ayesha@gmail.com",
"gpa": 3.5,
"got_job": false,
"statusID": "3a86016e-b0d6-479f-a1d1-1effa0846457",
"status": {
"is_enrolled": true,
"is_passed": false
},
"date_of_birth": "1998-07-17",
"exam_completed": 2
},
{
"id": "a2e5e97d-5f8d-493e-ba78-1701ca08d58e",
"name": "Arif",
"email": "arif@gmail.com",
"gpa": 3.51,
"got_job": true,
"statusID": "840a91da-75ce-4cd5-8a41-58081763a933",
"status": {
"is_enrolled": true,
"is_passed": false
},
"date_of_birth": "1998-03-27",
"exam_completed": 1
},
{
"id": "485b3f5a-8709-4902-82a6-4997c6a0839a",
"name": "Navin",
"email": "navin@gmail.com",
"gpa": 3.4,
"got_job": false,
"statusID": "0e437cee-92f6-418a-bf90-af74a67a9943",
"status": {
"is_enrolled": true,
"is_passed": false
},
"date_of_birth": "1993-06-24",
"exam_completed": 3
}
]
}
}
}
Using of filter argument: Filtering students by got_job
Using of filter argument: Filtering students by gpa
gpa{ ge: $point }: Go to the documentation explorer and click on the gpa field, we'll see some conditions with types like (ne: Float, ge: Float, eq: Float, etc.) We're using ge condition and its value is Float. That's why we've to take the float value
$point: Float: Specify the input value type because we can only match with float number according to ge: Float
Using of nested filter argument: Filtering students by gpa and got_job
Here we can use and / or / not operations. By default, and operation is applied on the query.
got_job : {eq: $job}, {exam_completed: {le: $exam}}: Data will show when got_job and exam_completed both satisfy conditions
Using of nested filter argument: Filtering students by got_job and exam_completed/email
got_job : {eq: $job}, or: [{exam_completed: {gt: $exam}}, {email: {eq: $email}}]: Data will show when got_job and exam_completed/email both satisfy conditions.
Using of limit & nextToken argument: Limiting data for pagination
$limit: Int:
- The limit argument takes an Integer value and gives a certain amount of data.
- Here we're providing the limit value 2. So the query will return a maximum of 2 documents/data.
$token: String:
- The nextToken argument takes a String value and gives the upcoming documents/data.
- Here we're providing an empty string in the argument because we need all data available in the first.
- We're also getting a nextToken string from the query field that will provide us with the upcoming data. If the nextToken value is null, that means we've no data left.
$limit: Int:
- Here we're providing the limit value 2. So the query will return a maximum of 2 documents/data.
$token: String:
- Get the nextToken string from the previous query and provide it in the nextToken argument field to get upcoming documents/data.
- We're also getting a new nextToken string from the query field that will provide us with the upcoming data.
Using of filter & limit & nextToken arguments:
We've already described all the conditions briefly, so now we will only visualize/understand the process.
Step-1| nextToken: "":
If the nextToken is an empty string, the limit process will start from 1st item/element.Step-2| limit: 2:
The limit process will select 1st & 2nd item/element.Step-3| filter: condition:
The filter process will check the 1st & 2nd item/element. If the filter condition satisfy, we will get the matched element. Here the condition matches with one element.
Step-1| nextToken: "":
If we provide a nextToken which we got from the previous query. The limit process will start from the upcoming item. Here the upcoming item starts from 3rd item/element.Step-2| limit: 2:
The limit process will select 3rd & 4th item/element.Step-3| filter: condition:
The filter process will check the 3rd & 4th item/element. If the filter condition satisfy, we will get the matched element. Here the condition matches with both elements.
Que: Here we are filtering data based on the student scalar field. What if we want to filter data based on student status (student object field)?
Solution:
Step-1: The connection between the Student model and the Status model is hasOne relation. We've to create a bi-directional relationship between the Student model and the Status model to get the Student data inside the Status model. If you don't understand relations between different models, check out this blog or feel free to comment below.
Step-2: We've created a bi-directional relationship between both models. But if we don't update documents one by one, we'll get a null value. To get the student data inside the status table, we've to update every status providing status id in $id field and student id in $student_id field.
With @searchable
directive
By adding @searchable we get some extra operations
- aggregation values, such as sum, average, min, max terms
- retrieve total search result count
- sort the search results across one or multiple fields
To work the @searchable directive properly, we've to setup OpenSearch, and that's for another blog
That's it for now. Thanks for your patience. If this blog help you please give a react.
Top comments (0)