DynamoDB Nested Query for Set of Object - java

I have a table called Group and it will have records like:
{
"id": "UniqueID1",
"name": "Ranjeeth",
"emailIdMappings": [
{
"emailId": "r.pt#r.com",
"userId": 324
},
{
"emailId": "r1.pt#r.com",
"userId": 325
}
]
},
{
"id": "UniqueID2",
"name": "Ranjeeth",
"emailIdMappings": [
{
"emailId": "r1.pt#r.com",
"userId": 325
},
{
"emailId": "r2.pt#r.com",
"userId": 326
}
]
}
I need to query and get result if emailId contains the input string.
I have reached so far and I am not able to get the result
AttributeValue attributeValue = new AttributeValue("r.pt#r.com");
Condition containsCondition = new Condition()
.withComparisonOperator(ComparisonOperator.CONTAINS)
.withAttributeValueList(attributeValue);
Map<String, Condition> conditions = newHashMap();
conditions.put("emailIdMappings.emailId", containsCondition);
ScanRequest scanRequest = new ScanRequest()
.withTableName("Group")
.withScanFilter(conditions);
amazonDynamoDB.scan(scanRequest)
dynamoDBMapper.marshallIntoObjects(Group.class, scanResult.getItems());
For the above code I am expecting record with id UniqueID1, but it's empty. If you pass "r1.pt#r.com" then you should get both records.
sdk used is com.amazonaws:aws-java-sdk-dynamodb:1.11.155
I tried posting the question in aws forum which didn't help much.

As you have List of Objects which has two attributes in a object (i.e. emailId and userId), you need to provide both values in order to match the item.
The CONTAINS function will not be able to match the item if the object has two attributes and only one attribute value mentioned in the filter expression.
Otherwise, you need to provide the occurrence (i.e. index) of the list to match the item.
Example:-
emailIdMappings[0].emailId = :emailIdVal

Related

Query DynamoDb Global Secondary Index

i am trying out dynamodb locally and got the following table:
"Table": {
"AttributeDefinitions": [
{
"AttributeName": "hashKey",
"AttributeType": "S"
},
{
"AttributeName": "sortKey",
"AttributeType": "S"
},
{
"AttributeName": "full_json",
"AttributeType": "S"
}
],
"TableName": "local",
"KeySchema": [
{
"AttributeName": "hashKey",
"KeyType": "HASH"
},
{
"AttributeName": "sortKey",
"KeyType": "RANGE"
}
],
"TableStatus": "ACTIVE",
"CreationDateTime": "2021-10-01T15:18:04.413000+02:00",
"ProvisionedThroughput": {
"LastIncreaseDateTime": "1970-01-01T01:00:00+01:00",
"LastDecreaseDateTime": "1970-01-01T01:00:00+01:00",
"NumberOfDecreasesToday": 0,
"ReadCapacityUnits": 5,
"WriteCapacityUnits": 1
},
"TableSizeBytes": 1066813,
"ItemCount": 23,
"TableArn": "arn:aws:dynamodb:ddblocal:000000000000:table/local",
"GlobalSecondaryIndexes": [
{
"IndexName": "sortKeyIndex",
"KeySchema": [
{
"AttributeName": "sortKey",
"KeyType": "HASH"
}
],
"Projection": {
"ProjectionType": "ALL"
},
"IndexStatus": "ACTIVE",
"ProvisionedThroughput": {
"ReadCapacityUnits": 10,
"WriteCapacityUnits": 1
},
"IndexSizeBytes": 1066813,
"ItemCount": 23,
"IndexArn": "arn:aws:dynamodb:ddblocal:000000000000:table/local/index/sortKeyIndex"
}
]
}
I want to query it with Java like this:
Index index = table.getIndex("sortKeyIndex");
ItemCollection<QueryOutcome> items2 = null;
QuerySpec querySpec = new QuerySpec();
querySpec.withKeyConditionExpression("sortKey > :end_date")
.withValueMap(new ValueMap().withString(":end_date","2021-06-30T07:49:22.000Z"));
items2 = index.query(querySpec);
But it throws a Exception with "QUery Key Condition not supported". I dont understand this, because in the docs, the "<" operator is described as regular operation. Can anybody help me
DDB Query() requires a key condition that includes an equality check on the hash/partition key.
You must provide the name of the partition key attribute and a single
value for that attribute. Query returns all items with that partition
key value. Optionally, you can provide a sort key attribute and use a
comparison operator to refine the search results.
In other words, the only time you can really use Query() is when you have a composite primary key (hash + sort).
Without a sort key specified as part of the key for the table/GSI, Query() acts just like GetItem() returning a single record with the given hash key.

Get json object in Array based on key and value in Java

I have a Json body like the example below. I need to extract the value from a key that has another key with a specific value in an array. I am passing in a JsonNode with everything in the detail component of the message, I can easily extract from each level, however, I'm struggling with the array.
In this case, I need to extract the value of "value" (Police/Fire/Accident Report) from the object in the array which has a key/value pair of "name":"documentTitle". I understand this is a JSONArray, but I can't find a good example that shows me how to extract the values for an object in the array that contains a certain key/value pair, I don't think I can rely on getting the object in position [2] in the array as the same objects may not always be present in the additionalMetadata array.
Sample Json:
"sourceVersion": "1.0",
"eventId": "8d74b892-810a-47c3-882b-6e641fd509eb",
"clientRequestId": "b84f3a7b-03cc-4848-a1e8-3519106c6fcb",
"detail": {
"stack": "corona",
"visibilityIndicator": null,
"documentUid": "b84f3a7b-03cc-4848-a1e8-3519106c6fcb",
"additionalMetadata": [
{
"name": "lastModifiedDate",
"value": "2021-05-21T04:53:53Z"
},
{
"name": "documentName",
"value": "Police/Fire Report, 23850413, 2021-05-20 14:51:23"
},
{
"name": "documentTitle",
"value": "Police/Fire/Accident Report"
},
{
"name": "documentAuthor",
"value": "System Generated"
},
{
"name": "lastModifiedBy",
"value": "System Updated"
},
{
"name": "createdBy",
"value": "System Generated"
},
{
"name": "documentDescription",
"value": "Police/Fire Report received"
},
{
"name": "organizationCode",
"value": "Claims"
}
]
}
}```
Loop through the json array and extract the json object with name documentTitile. From that json object you can get the value
Well, either the JSON framework you're using supports this out of the box (check the documentation) or you could convert it manually to a map:
List<AdditionalMetadataEntry> additionalMetadata;
[...]
Map<String, String> additionalMetadataMap = additionalMetadata.stream().collect(Collectors.toMap(AdditionalMetadataEntry::getName, AdditionalMetadataEntry::getValue));
I was able to figure it out. I created a new node off the existing notificationBody JsonNode, then parsed through the metadata key/value pairs:
String docTitle = "";
JsonNode additionalMetadata = notificationBody.get("detail").get("additionalMetadata");
for (JsonNode node: additionalMetadata) {
String name = node.get("name").asText();
String value = node.get("value").asText();
if(name.equals("documentTitle")){
docTitle = value;
}
}

Deserialize complex json body, validate one element in it, then through that, map to another element (JAVA) is it possible?

I have a json array to work with, like so:
[
{
"id": "12345",
"eauthId": "123451234512345123451234512345",
"firstName": "Jane",
"middieInitial": "M",
"lastName": "Doe",
"email": "janedoe#usda.gov",
"roles": [
{
"id": "CTIS_ROLE_ID",
"name": "A test role for CTIS",
"treatmentName": "Fumigation"
}
]
},
{
"id": "67890",
"eauthId": "678906789067890678906789067890",
"firstName": "John",
"middieInitial": "Q",
"lastName": "Admin",
"email": "johnadmin#usda.gov",
"roles": [
{
"id": "CTIS_ADMIN",
"name": "An admin role for CTIS",
"treatmentName": "System Administration"
}
]
}
]
My task is to find out the user's "roles" --> "name", once match, get that user's email address and sign in using that email address. It seems like a simple task, but it has been really kicking my bottom, since digging into API is new to me. I've tried different libraries (Jackson, RestAssured, Json Simple) and finally GSon. I don't have time to sit and study everything from the scratch. I just needed a quick solution. But it definitely hasn't been quick. Is anyone kind enough to help me out with this. I'd really appreciate it.
closeableHttpResponse = restClient.get(ConfigurationReader.get("base_url") + ConfigurationReader.get("user_endpoint"));
//Status code
int statusCode = closeableHttpResponse.getStatusLine().getStatusCode();
System.out.println("statusCode = " + statusCode);
String responseString = EntityUtils.toString(closeableHttpResponse.getEntity(), "UTF-8");
Type userListType = new TypeToken<List<Users>>(){}.getType();
List<Users> users = (List<Users>) new Gson().fromJson(responseString, userListType);
Roles roles = new Gson().fromJson(responseString, Roles.class);
it gives me this error
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:226)
at com.google.gson.Gson.fromJson(Gson.java:932)
The problem with your code is
Type userListType = new TypeToken<List>(){}.getType();
List users = (List) new Gson().fromJson(responseString, userListType);
You are not receiving just a list, you are actually deserializing an array of lists.
So try this:
List[] users = (List[]) new Gson().fromJson(responseString, List[].class);

Save JSON request as Item in dynamoDb

I have a request of the following JSON format:
{
"profile": {
"created": 1505202655,
"createdBy": "abc",
"updated": 1505202655,
"updatedBy": "xyz"
},
"likesId": [
"0010127916"
],
"icon": null,
"Attributes": {
"backgroundColor": "#FFFFFF",
"logo": "images/Logos/P0010127916.jpg",
"textColor": "#000000"
},
"profileId": "PACYG0010916",
"restrictions": {
"clients": [
"Android",
"SmartTv"
],
"UserTypes": [
"user1",
"user2"
],
"periodEnd": 1512978849,
"periodStart": 1505202849
},
}
I am trying to save the above JSON request Object in the dynamoDb table using putItem. However I am stuck in some issues which are as follows:
Can I store this whole JSON request as-is(without escaping double quotes) in the form of item in dynamodb table?
In case of likesId and Attributes I am storing them as a List and Map with the help of .withList and .withMap methods respectively, but in case of profile I have taken it as a POJO which has 4 states, how can I save this object with the putItem as I did not find any method for saving objects like this, as we have methods for string, numbers and other datatypes, how can I save my own object?
Any kind of guidance will be highly appreciated as I am new to dynamoDb and learning it by doing POC.
You should be able to save it quite easily with the DocumentClient class:
http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html#put-property
var params = {
TableName : 'Table',
Item: item
};
var documentClient = new AWS.DynamoDB.DocumentClient();
documentClient.put(params, function(err, data) {
if (err) console.log(err);
else console.log(data);
});
Where item is the object from your original question

Elasticsearch java client search nested field not working

I am able to successfully create an index using java api and search the source field. My Problem is not able to get the nested key field using search.
For ex my sample json stucture:
{
"name": "John Smith",
"age": 42,
"confirmed": true,
"join_date": "2014-06-01",
"timestamp": "14331222299",
"home": {
"lat": 51.5,
"lon": 0.1
},
"accounts": [
{
"type": "facebook",
"id": "johnsmith"
},
{
"type": "twitter",
"id": "johnsmith"
}
]
}
i can able to index this json as source through java client api:-
IndexResponse response = client.prepareIndex(mohan+"-"+14-10-2014, "mohanelastic")
.setSource(jsonoutput.toString())
.execute()
.actionGet();
My java client search api:
QueryBuilder en = QueryBuilders.matchQuery("name", "John Smith");
FilterBuilder flb = FilterBuilders.andFilter(
FilterBuilders
. .rangeFilter("timestamp").from(starttimeinmilli).to(endtimeinmilli),
FilterBuilders.queryFilter(QueryBuilders.matchQuery("confirmed", "true"))
);
SearchResponse response = client.prepareSearch(mohan+"-"+14-10-2014)
.setTypes("mohanelastic")
.setSearchType(SearchType.QUERY_AND_FETCH)
.setPostFilter(flb)
.setQuery(en)
.setFrom(0).setSize(60)
.execute().actionGet();
In this i can able to get the total hits, key field values(name,age,join_date). But not able to get the key value for (home.lat) it shows null value. Nested values for any json shows null.
I am retrieving the source field json keys and it shows respective value:-
System.out.println("event type"+response.getHits().getAt(0).getSource().get("name"));
System.out.println("event type"+response.getHits().getAt(0).getSource().get("timestamp"));
But when i try home.lat it shows null value:
System.out.println("event type"+response.getHits().getAt(0).getSource().get("home.lat"));
You can't access home.lat value using dot notation in the Java API. Think of nested objects as maps (home) or a list containing maps (accounts). To get the lat value you would need to do the following:
Map<String, Object> source = response.getHits().getAt(0).getSource();
Map<String, Object> home = source.get('home');
Double latValue = (Double) home.get('lat');

Categories