Is the following normal with SDN?
.../api/friendships/2 returns following so I do have a friendship there with the id 2:
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/api/friendships/2"
},
"requester" : {
"href" : "http://localhost:8080/api/friendships/2/requester"
},
"confirmer" : {
"href" : "http://localhost:8080/api/friendships/2/confirmer"
}
}
}
But .../api/friendships returns following so it does not show this friendship with id 2:
{
"_links" : {
"self" : {
"href" : "http://localhost:8080/api/friendships{?page,size,sort}",
"templated" : true
}
},
"page" : {
"size" : 20,
"totalElements" : 0,
"totalPages" : 0,
"number" : 0
}
}
Related
I have a graphQL schema like this:
type Post {
id: String!
title: String!
content: String!
user: User!
}
type Query {
allPosts: [Post!]
singlePost(id: String!): Post!
}
type User {
name: String!
posts: [Post!]
}
The dynamo DataSource handles queries. In the query below, the user will be handled with a different resolver because it depends on different GSI.
query MyQuery {
allPosts {
content
title
user{
name
}
}
}
allPosts resolver looks like this:
{
"version" : "2017-02-28",
"operation" : "Query",
"query" : {
"expression" : "#t = :sk",
"expressionNames" : {
"#t": "type"
},
"expressionValues" : {
":sk": $util.dynamodb.toDynamoDBJson("post")
}
},
"index" : "GSI",
"select" : "ALL_ATTRIBUTES"
}
The resolver for user in the Post type is:
{
"version" : "2017-02-28",
"operation" : "Query",
"query" : {
"expression" : "PK = :pk AND SK = :sk",
"expressionValues" : {
":pk": "NEED TO ACCESS THE Partition KEY FROM ALL_POSTS",
":sk": $util.dynamodb.toDynamoDBJson("profile")
}
},
"select" : "ALL_ATTRIBUTES"
}
I need to access the partition key from the post object in each iteration to fetch the user of a specific id, just like the author resolver in this code (https://github.com/benawad/graphql-n-plus-one-example/blob/master/src/index.js):
const resolvers = {
Book: {
author: async parent => {
const author = await knex("users")
.select()
.where("id", parent.authorId)
.first();
return author;
}
},
Query: {
books: async () => {
const books = await knex("books")
.select()
.limit(10);
return books;
}
}
};
I've found the answer finally, the required object is stored in $ctx.source. All I had to do is to change the user resolver to this (Provided the result object have PK inside it):
{
"version" : "2017-02-28",
"operation" : "Query",
"query" : {
"expression" : "PK = :pk AND SK = :sk",
"expressionValues" : {
":pk": $util.dynamodb.toDynamoDBJson($ctx.source.PK),
":sk": $util.dynamodb.toDynamoDBJson("profile")
}
},
"select" : "ALL_ATTRIBUTES"
}
The $context.source references the parent object of the current field that’s being resolved. In this example, $ctx.source.PK refers to the individual Post object, which is then used for the query expression. ($context and $ctx are same). It works exactly like the parent argument in the apollo-server framework.
I'm trying to get a record from a GSI and I'm stucked.
API Schema:
type DriverInfos {
id: String!
status: Int
lastLat: Float
lastLng: Float
idDriver: String # GSI
}
type Query {
getDriverInfosByDriver(idDriver: String): DriverInfos
}
Resolver :
{
"version" : "2017-02-28",
"operation" : "Query",
"index" : "idDriver-index",
"query" : {
## Provide a query expression. **
"expression": "#idDriver = :idDriver",
"expressionNames" : {
"#idDriver" : "idDriver"
},
"expressionValues" : {
":idDriver" : {
"S" : "${ctx.args.idDriver}"
}
}
}
}
Query :
query getDriverInfosByDriver{
getDriverInfosByDriver(idDriver: "1")
{
idDriver
status
lastLat
lastLng
}
}
Return :
{
"data": {
"getDriverInfosByDriver": {
"idDriver": null,
"status": null,
"lastLat": null,
"lastLng": null
}
}
}
GSI is well activated : Name : "idDriver-index" - PartitionKey : idDriver (String)
Try with other ids : 2, 3, ...
It seems that it comes from the resolver. I tried with different resolver but it always return an error.
Thank you in advance for your answers.
The issue is that a Query operation always returns a set of results not just one. If you want to leave your query type like this:
type Query {
getDriverInfosByDriver(idDriver: String): DriverInfos
}
then you should to change your response mapping template to this:
#if($ctx.result.items.size() > 0)
$util.toJson($ctx.result.items[0])
#else
null
#end
If instead the getDriverInfosByDriver query should return multiple info objects then you should change your schema to:
type DriverInfo {
id: String!
status: Int
lastLat: Float
lastLng: Float
idDriver: String # GSI
}
type DriverInfoConnection {
items: [DriverInfo]
nextToken:String
}
type Query {
getDriverInfosByDriver(idDriver: String): DriverInfoConnection
}
You can then leave your response mapping template as the default:
$util.toJson($ctx.result)
and then query it like so
query getDriverInfosByDriver{
getDriverInfosByDriver(idDriver: "1") {
items {
idDriver
status
lastLat
lastLng
}
}
}
I'm building app with Ionic and angulfire2 and I'm trying to join multiple references from firebase by using the object key.
Database looks following:
{
"achievements" : {
"200" : {
"authorId" : "nGSlhjaDRKh8XdrgxcusU0wdiHN2",
"description" : "I did it"
}
},
"challengeAchievements" : {
"100" : {
"200" : true
}
},
"challenges" : {
"100" : {
"name" : "test challenge"
},
"101" : {
"name" : "test challenge 2"
}
},
"users" : {
"nGSlhjaDRKh8XdrgxcusU0wdiHN2" : {
"email" : "user1#test.com"
},
"wBMX8WOHIpM7dEkzj0hM19OPMbs1" : {
"email" : "user2#test.com"
}
}
}
I would like to join all this data together so that from challenges you get achievements, and from achievements you get the user data.
Currently I'm able to get the achievement details, but not the user data. My provider looks like this at the moment:
getChallengeAchievements(challengeKey) {
return this.rtdb.list(`/challengeAchievements/${challengeKey}`)
.map(achievements => achievements.map((achievement) => {
if (achievement.key)
achievement.details = this.getAchievementDetails(achievement.key);
achievement.user = this.getAchievementUserDetails(achievement.details.authorId);
return achievement;
}));
}
getAchievementDetails(achievementKey?: string): Observable<any> {
if (achievementKey)
return this.rtdb.object(`/achievements/${achievementKey}`);
}
getAchievementUserDetails(authorId?: string): Observable<any> {
if (authorId)
return this.rtdb.object(`/users/${authorId}`);
else console.log('Not found');
}
How should I structure the authorId query in this function? If I use static value in
achievement.details.authorId('nGSlhjaDRKh8XdrgxcusU0wdiHN2')
I'm able to receive the data.
Solved it by subscribing to the first join "achievement.details" and obtaining the user data from there.
getChallengeAchievements(challengeKey) {
return this.rtdb.list(`/challengeAchievements/${challengeKey}`)
.map(achievements => achievements.map((achievement) => {
if (achievement.key)
achievement.details = this.getAchievementDetails(achievement.key);
achievement.details.subscribe(
details => {
achievement.user = this.getAchievementUserDetails(details.authorId);
})
return achievement;
}));
}
import Foundation
import ObjectMapper
class MemberActivityCollection: Mappable
{
var TotalRows : Int = 0
var MemberActivityList : Array<MemberActivity> = Array()
var MemberID: Int = 0
init(){ }
internal required init?(map: Map) { }
// Mappable
func mapping(map: Map) {
MemberActivityList <- map["MemberActivityList"]
TotalRows <- map["TotalRows"]
MemberID <- map["MemberID"]
}
}
class MemberActivity: Mappable
{
var ActivityID: Int = 0
var fk_MemberID: Int = 0
var ActivityDate: String!
var ActivityFrom: String!
var ActivityTo: String!
var AvgPace: String!
init(){ }
internal required init?(map: Map) { }
// Mappable
func mapping(map: Map) {
ActivityID <- map["ActivityID"]
fk_MemberID <- map["fk_MemberID"]
ActivityDate <- map["ActivityDate"]
ActivityFrom <- map["ActivityFrom"]
ActivityTo <- map["ActivityTo"]
AvgPace <- map["AvgPace"]
}
}
Please Note : The MemberActivityCollection Class has Array of MemberActivity Class
Need to Parse the JSON as MemberActivityCollection
{
"TotalRows" : 16,
"MemberActivityList" : [
{
"fk_MemberID" : 47,
"ActivityID" : 29,
"ActivityFrom" : "18:30:00",
"ActivityTo" : "14:30:00",
"AvgPace" : "3.00"
},
{
"fk_MemberID" : 47,
"ActivityID" : 26,
"ActivityFrom" : "01:07:46",
"ActivityTo" : "05:07:00",
"AvgPace" : "5.00"
},
{
"fk_MemberID" : 47,
"ActivityID" : 35,
"ActivityFrom" : "09:30:00",
"ActivityTo" : "04:15:00",
"AvgPace" : "0.06"
}
],
"MemberID" : 47
}
Using the following code to map the json to object of MemberActivityCollection Class
Am I declaring the property MemberActivityList wrong way??
The whole idea is to map the json in MemberActivityCollection class so that one of its property ("MemberActivityList") can hold the detailed data
To Achieve that I wrote following lines of code and not getting the desired output (As mentioned in the above line).
let objMAC : MemberActivityCollection = Mapper<MemberActivityCollection>().map(JSONObject: jsonData)! //Datatype of jsonData variable is JSON
The above statement throws error message that 'EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP, subcode=0x0'
Please explain the correct way to achieve this.
I'm new to DynamoDB, I'm trying to insert a new item. However, I'm getting the following exception:
com.amazonaws.services.dynamodbv2.model.AmazonDynamoDBException: The provided key element does not match the schema (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException; Request ID: XXX)
This is how my table is described:
{
"Table": {
"TableArn": "arn:aws:dynamodb:us-east-1:111:table/table-XXX",
"AttributeDefinitions": [
{
"AttributeName": "timestamp",
"AttributeType": "S"
},
{
"AttributeName": "title",
"AttributeType": "S"
}
],
"ProvisionedThroughput": {
"NumberOfDecreasesToday": 0,
"WriteCapacityUnits": 5,
"ReadCapacityUnits": 5
},
"TableSizeBytes": 0,
"TableName": "ddb-table-sst67gy",
"TableStatus": "ACTIVE",
"KeySchema": [
{
"KeyType": "HASH",
"AttributeName": "title"
},
{
"KeyType": "RANGE",
"AttributeName": "timestamp"
}
],
"ItemCount": 0,
"CreationDateTime": 1489090172.658
}
}
And this is my Java class:
#DynamoDBTable(tableName = "table-XXX")
public class Movie {
private String title;
private String timeStamp;
#DynamoDBHashKey(attributeName = "title")
#NotNull(message = "Title must not be empty")
public String getTitle() {
return title;
}
public Movie withTitle(String name) {
setTitle(name);
return this;
}
#DynamoDBAttribute(attributeName = "timestamp")
public String getTimeStamp() {
return timeStamp;
}
public Movie withTimeStamp(String address) {
setTimeStamp(address);
return this;
}
public void setTitle(String title) {
this.title = title;
}
public void setTimeStamp(String timeStamp) {
this.timeStamp = timeStamp;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Movie movie = (Movie) o;
if (title != null ? !title.equals(movie.title) : movie.title != null) return false;
return timeStamp != null ? timeStamp.equals(movie.timeStamp) : movie.timeStamp == null;
}
#Override
public int hashCode() {
int result = title != null ? title.hashCode() : 0;
result = 31 * result + (timeStamp != null ? timeStamp.hashCode() : 0);
return result;
}
}
How should I map my Java class into DynamoDB correctly ?
Please use annotation #DynamoDBRangeKey to define the range or sort key attribute.
#DynamoDBRangeKey(attributeName = "timestamp")
public String getTimeStamp() {
return timeStamp;
}