AppSync/GraphQL filter nested objects - graphql

I have a DynamoDB table with the following structure
site (String)
addresses (List)
|-> address (String)
|-> isCurrent (Boolean)
I want to filter a specific site for either current or all address(s).
query MyQuery {
getSite(site: "site1", isCurrent: true) {
site
addresses{
adress
isCurrent
}
the schema looks like
type Sites{
site: String!
addresses: [Address]
}
type Address {
address: String
isCurrent: Boolean
}
type Query{
getSite(site: String!, isCurrent:Boolean)
}
The Resolver I have
#if($ctx.args.isCurrent)
{
"version": "2017-02-28",
"operation": "Query",
"query": {. // Filter for specific Site
"expression": "#siteName = :siteNameByUser",
"expressionNames": {
"#siteName": "site"
},
"expressionValues": {
":siteNameByUser": {"S": $util.toJson($ctx.args.site)}
}
}, // Filter Current Address(s)
"filter": {
"expression": "addresses.isCurrent = :isActiveByUser",
"expressionValues": {
":isActiveByUser": $util.dynamodb.toDynamoDBJson($ctx.args.isCurrent)
}
}
}
#else
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"site": $util.dynamodb.toDynamoDBJson($ctx.args.site)
}
}
#end
I'm not getting any results when I add filter ( it works without the filter or with isCurrent=False ).
I am trying to filter the inner objects in Addresses list based on a value user sends for isCurrent. Any help is much appreciated!
I tried writing a resolver with a filter condition on an inner value (addresses.isCurrent).
{
"version": "2017-02-28",
"operation": "Query",
"query": {. // Filter for specific Site
"expression": "#siteName = :siteNameByUser",
"expressionNames": {
"#siteName": "site"
},
"expressionValues": {
":siteNameByUser": {"S": $util.toJson($ctx.args.site)}
}
}, // Filter Current Address(s)
"filter": {
"expression": "addresses.isCurrent = :isActiveByUser",
"expressionValues": {
":isActiveByUser": $util.dynamodb.toDynamoDBJson($ctx.args.isCurrent)
}
}
}

Apparently, DynamoDB does not let you filter on Complex object types like List of Maps (your case), see a related question: DynamoDB: How to store a list of items
I'd suggest changing your DynamoDB table data model if possible to site, address, isCurrentAddress to achieve what you are trying to do. Or you can
write logic in VTL response mapping template to filter your result set based on isCurrentAddress value. Btw AppSync recently launched JavaScript resolvers, go through that and see if that helps in writing your resolver logic simpler.

Related

Why does this AWS AppSync list operation using OR return an empty list even when part of the OR returns truthy values?

Context:
I am trying to query for all notifications sent or received by a user in my mobile app, and am getting results that (I think) show that AWS AppSync's OR filtering is slightly broken (or that I do not understand how it works)
Note that I am performing these queries using AWS AppSync Queries, but the results are consistent when using their GUI or by sending the queries from the React Native app
Here is my list query using the OR statement
query listAllNotifsForUser {
listNotifications(filter: {sentUserID: {eq: "arbitrary-id-1"}, or: {receivedUserID: {eq: "arbitrary-id-1"}}}) {
items {
id
}
nextToken
}
}
This query returns
"data": {
"listNotifications": {
"items": [],
"nextToken": null
}
Here is my query when listing specifically notifications that have the sentUserID equal to arbitrary-id-1 (no OR statement, only the first half of the OR filter from above)
query listAllNotifsForUser {
listNotifications(filter: {sentUserID: {eq: "arbitrary-id-1"}}) {
items {
id
}
nextToken
}
}
and here is the result from that query
{
"data": {
"listNotifications": {
"items": [
{
"id": "88d204c8-7346-4f69-bc6a-c1e5db1ce5f4"
},
{
"id": "29e03351-75f0-46b2-933b-c3cca43a6067"
},
{
"id": "e21cf81a-7cb3-4331-90af-6ef266f75820"
},
{
"id": "17b42150-ae7c-4852-a58c-85d73ed2e247"
}
],
"nextToken": null
}
}
}
Notice the ONLY difference between these two queries is the removal of the 'or' and the second half of the boolean check, which from basic knowledge of programming, one would not imagine this should ever limit the results compared to a single boolean statement
Any thoughts?
I did this on my AppSync console and it worked:
query MyQuery {
listJobListings(filter: {or: [{ city: {eq: "Chongqing City"} }, { city: {eq: "Beijing"} }]}) {
nextToken
items {
city
}
}
}
Which means you'll need to do this:
query listAllNotifsForUser {
listNotifications(filter: {or: [{ sentUserID: {eq: "user-id"} }, { sentUserID: {eq: "user-id"} }]}) {
items {
id
}
nextToken
}
}
More information here

grpc/protobuffer ask for specific fields

GraphQL lets you ask for specific fields, the response contains only the fields that you had asked for. For example:
a graphql query like:
{
hero {
name
}
}
will return:
{
"data": {
"hero": {
"name": "R2-D2"
}
}
}
where as a graphQl query like:
{
hero {
name
friends {
name
}
}
}
would return:
{
"data": {
"hero": {
"name": "R2-D2",
"friends": [
{
"name": "Luke"
},
{
"name": "Han Solo"
},
{
"name": "Leia"
}
]
}
}
}
Is there a similar mechanism/library/pattern that can be used in gRPC to achieve the same?
FieldMask is similar in protobuf. It is a list of fields to retain, so the first example would be paths: "hero.name" and the second would be paths: ["hero.name", "hero.friends.name"].
It is probably most frequently used to specify which fields should be changed in an update. But it can equally be used to specify the fields that should be returned.
The server can either process the FieldMask directly (e.g., only using the listed fields in a SELECT SQL query), or it can retrieve all the information and filter the result using FieldMaskUtil.merge() to copy just the requested fields into a new proto message to return to the client.

Nested query in Strapi GraphQL

I have a document structured as follows, more or less:
post {
_id
title
isPublished
}
user {
_id
username
name
[posts]
}
I know I can query fields like postConnection and userConnection with the aggregate subfield in order to query a count of all objects. But how do I get the total count of all posts by a given user?
I was able to come up with this:
{
postsConnection(where: {isPublished: true}){
groupBy{
author{
key
connection{
aggregate{
count
}
}
}
}
}
}
But this returns (expectedly) something like this:
{
"data": {
"postsConnection": {
"groupBy": {
"author": [
{
"key": "5c9136976238de2cc029b5d3",
"connection": {
"aggregate": {
"count": 5
}
}
},
{
"key": "5c99d5d5fcf70010b75c07d5",
"connection": {
"aggregate": {
"count": 3
}
}
}
]
}
}
}
}
As you can see, it returns post counts for all authors in an array. What I need is to be able to return the count for only one specific user and not by _id (which is what the key field seems to map to) but by another unique field I have in the users collection, i.e. username.
Is that possible?
Need to pass in a parameter to either the query or the field to return specific data

Is there any way to query products using dynamic filters in Magento 2.3 graphql endpoint?

I was looking at the new graphql endpoint exposed by Magento 2.3.1 and above at the query for listing products:
query products(
pageSize:6,
currentPage:1,
filter:{
category_id: { eq: "3" }
}
) {
filters {
name
request_var
filter_items_count
filter_items {
label value_string
}
}
items {
id
name
small_image {
url
}
# ...
}
# ...
}
The response body yields products in the items property just as expected and a bunch of custom filters in an array in the filters property which look like this:
"filters": [
{
"name": "Activity",
"request_var": "activity",
"filter_items_count": 12,
"filter_items": [
{
"label": "Outdoor",
"value_string": "5"
},
{
"label": "Yoga",
"value_string": "8"
},
{
"label": "Recreation",
"value_string": "9"
},
// rest of filter values
]
},
// rest of filters
]
Given the fact that those filters are dynamic and user defined is there a way of sending them back with a list products query in graphql? I would expect to have a property somewhere under the products query that could be an array of aforementioned filter objects but so far I haven't found anything neither in the schema nor in the official documentation.
Did anyone have any similar experience with this?
No. Theres no way of getting the filtered options sent back. There are options where you can return the additional filtering abilities (similar to when you are viewing a category page) to return list of ways to filter but nothing that returns the current active filters in place.
{
products(filter: {sku: {like: "%"} } pageSize: 500) {
filters{
request_var
name
filter_items{
label
value_string
}
}
items {
id
sku
name
...
}
}
}

Spring Data ElasticSearch Build In IN query returning partial match

I am new to elastic search spring data, Today I was trying to get In query working with Spring data ES repository.
I have to do a lookup for list of user names, and if its exactly match in the index, need to get those users back as result.
I tried to use the built in repository 'In' method to do so, but it returns partial matches, please help me to make this working like SQL IN query.
Here is my repository code:
public interface UserRepository extends ElasticsearchRepository<EsUser, String>
{
public List<EsUser> findByUserAccountUserNameIn(Collection<String> terms);
}
REQUEST:
{"terms":["vijay", "arun"], "type":"NAME"}
RESPONSE:
[
{
"userId": "236000",
"fbId": "",
"userAccount": {
"userName": "arun",
"urlFriendlyName": "arun",
},
"userProfile": {
},
"userStats": {
}
},
{
"userId": "6228",
"userAccount": {
"userName": "vijay",
"urlFriendlyName": "vijay",
},
"userProfile": {
},
"userStats": {
}
},
{
"userId": "236000",
"fbId": "",
"userAccount": {
"userName": "arun singh",
"urlFriendlyName": "arun-singh",
},
"userProfile": {
},
"userStats": {
}
}
{
"userId": "236000",
"fbId": "",
"userAccount": {
"userName": "vijay mohan",
"urlFriendlyName": "vijay-mohan",
},
"userProfile": {
},
"userStats": {
}
}
]
This is because your userAccount.userName field is an analyzed string, and thus, the two tokens arun and singh have been indexed. Your query then matches the first token, which is normal.
In order to prevent this and guarantee an exact match you need to declare your field as not_analyzed, like this:
#Field(index = FieldIndex.not_analyzed)
private String userName;
Then you'll need to delete your index and the associated template in /_template, restart your application so a new template and index are created with the proper field mapping.
Then your query will work.

Resources