AWS Java SDK DynamoDB update expression for a "complex" item - java

So I have the following item where testId is the sort key:
{
"userId": "admin",
"testId": "1234",
"picture": "abstract",
"numOfUsers": 1,
"Tests": [
{
"duration": 1234,
"typeId": "2345",
"interval": 450000,
"quantity": 333333
},
{
"duration": 1234,
"typeId": "6789",
"interval": 450000,
"quantity": 333333
},
{
"duration": 1234,
"typeId": "2020",
"interval": 450000,
"quantity": 333333
}
]
}
As you can see, there are a few identical items under tests. My question is how do I update all of them with the same value? What I mean by that is that, for example, I would like to update duration on all three objects from 1234 to 2222.
Here is the code I've tested:
Table table = dynamoDB.getTable(tableName);
Map<String, String> expressionAttributeNames = new HashMap<String, String>();
expressionAttributeNames.put("#A", "Duration");
Map<String, Object> expressionAttributeValues = new HashMap<String, Object>();
expressionAttributeValues.put(":val1", "2222");
UpdateItemOutcome outcome = table.updateItem(
"testId",
"1234",
"set #A :val1",
expressionAttributeNames,
expressionAttributeValues);
Any help would be appreciated :)

Based on my understanding of DynamoDb and Expressions, is that you need to tell dynamodb to drill into the attribute you want.
Your code is telling it to update Duration...but where is Duration? It is not at the top level of the item.
See if this would work:
Table table = dynamoDB.getTable(tableName);
Map<String, String> expressionAttributeNames = new HashMap<String, String>();
expressionAttributeNames.put("#Dur", "duration");
expressionAttributeNames.put("#Test", "Tests");
Map<String, Object> expressionAttributeValues = new HashMap<String, Object>();
expressionAttributeValues.put(":val1", "2222");
UpdateItemOutcome outcome = table.updateItem(
"testId",
"1234",
"set #Test.#Dur :val1",
expressionAttributeNames,
expressionAttributeValues);
=== Edited ===
ValueMap valueMap = new ValueMap().withNumber(":dur", 2222));
UpdateItemSpec updateItemSpec = new UpdateItemSpec()
.withPrimaryKey("key", year)
.withUpdateExpression("set Tests.duration = :dur")
.withValueMap(valueMap)
.withReturnValues(ReturnValue.UPDATED_NEW);
UpdateItemOutcome updateItemOutcome = table.updateItem(updateItemSpec);
=== Edited ====
UpdateItemSpec updateItemSpec = new UpdateItemSpec()
.withPrimaryKey("key", "primaryKey")
.withUpdateExpression("set Tests.#duration = :value")
.withNameMap(new NameMap().with("#duration", "duration"))
.withValueMap(new ValueMap().withNumber(":value", 2222))
.withReturnValues(ReturnValue.UPDATED_NEW);

Related

How to wrap object in array in java?

I'm making a code to send data to the payment gateway. I am a beginner in using java. I'm having a bit of trouble working with objects in an array in the item_details parameter. I've made the code as below.
public KeyValuePair<String, String> requestSnapToken(String orderNo,
BigDecimal grossAmount, int paymentMethodId,
String firstName,
String email,
List<FormCartLine> itemDetails
) {
return FAILSAFE_EXECUTOR.get(() -> {
String midtransOrderId = orderNo;
Builder<String, Object> custDetailBuilder = new ImmutableMap.Builder<String, Object>()
.put("first_name", firstName)
.put("last_name", "");
Builder<String, Object> itemDetailsBuilder = new ImmutableMap.Builder<String, Object>();
for (int i = 0; i < itemDetails.size(); i++) {
FormCartLine line = itemDetails.get(i);
int row = i + 1;
itemDetailsBuilder.put($("id%s", row), line.getProductId())
.put($("price%s", row), line.getUnitPricePreTax())
.put($("quantity%s", row), line.getQty())
.put($("name%s", row), line.getName())
.put($("brand%s", row), line.getBrandName())
.put($("category%s", row), line.getCategoryName());
}
Builder<String, Object> payloadBuilder = new ImmutableMap.Builder<String, Object>()
.put("transaction_details", new ImmutableMap.Builder<String, Object>()
.put("order_id", midtransOrderId)
.put("gross_amount", String.valueOf(grossAmount.longValue()))
.build())
.put("item_details", itemDetailsBuilder.build())
});
}
I tried to debug from the code that I made, the payload looks like this. This is not what I wanted..
"transaction_details" : {
"order_id" : "S415",
"gross_amount" : "194547"
},
"item_details" : {
"id1" : "001",
"price1" : 200,
"quantity1" : 1,
"name1" : "Dummy 1",
"brand1" : "Dummy",
"category1" : "Dummies",
"id2" : "002",
"price2" : 300,
"quantity2" : 1,
"name2" : "Dummy 2",
"brand2" : "Dummy",
"category2" : "Dummies"
},
what i want is like below. How do I implement it in java?
"transaction_details" : {
"order_id" : "S415",
"gross_amount" : "194547"
},
"item_details" : [{
"id" : "001",
"price" : 200,
"quantity" : 1,
"name" : "Dummy 1",
"brand" : "Dummy",
"category" : "Dummies"
},
{
"id" : "002",
"price" : 300,
"quantity" : 1,
"name" : "Dummy 2",
"brand" : "Dummy",
"category" : "Dummies"
}
]
Build separate maps for each of your objects and put those maps into a list. Immutability is probably not required, so I'll simplify by using an ArrayList:
final List<Map<String, Object>> itemDetailsList = new ArrayList<>(itemDetails.size());
for (final FormCartLine line : itemDetails) {
itemDetailsList.add(Map.ofEntries(
Map.entry("id", line.getProductId()),
Map.entry("price", line.getUnitPricePreTax()),
// etc.
));
}
// ...
Builder<String, Object> payloadBuilder = new ImmutableMap.Builder<String, Object>()
// .put(...)
.put("item_details", itemDetailsList)
Note that the map returned by Map.ofEntries cannot hold null values, so if that's a requirement, you need to switch to a HashMap<String, Object> or another map type with support for null values.
Of course, you can use an ImmutableMap.Builder too if you prefer or the loop could be converted to use the Java stream API.

Fixture Generator For 8 Groups in Java

There are 4 different teams in 8 different groups that I created with Hashmap. I want 4 teams in each group to play a total of 12 matches, GetAway(away game) and GetHome(home game). I created a fixtur generator. I want to make separate rounds for each 8 groups. How do I create fixtures with the 8 groups I created?In the matches between the teams, the goals will be random.
Map<String, String> bagOne = Map.of("Bayern Munich", "Germany", "Sevilla", "Spaın", "Real Madrid", "Spaın", "Liverpool", "England", "Juventus", "Italy", "Paris Saint", "France", "Zenit", "Rusia", "Porto", "Rusia");
Map<String, String> bagTwo = Map.of("Barselona", "Spaın", "Atletico Madrid", "Spaın", "Manchester City", "England", "Manchester United", "England", "Borussia Dortmund", "Germany", "Shakhtar Donetsk", "Ukrayna", "Chelsea", "England", "Ajax", "Hollanda");
Map<String, String> bagThree = Map.of("Dynamo Kiev", "Ukrayna", "Redbull Salzburg", "Germany", "RB Leibzig", "Germany", "Internazionale", "Italy", "Olympiacos", "Italy", "Lazio", "Italy", "Krasnodar", "Rusia", "Atalanta", "Italy");
Map<String, String> bagFour = Map.of("Lokomotiv M", "Rusia", "Marseille", "France", "Club Brugge", "Belçika", "BorMönchengladbach", "Germany", "Galatasaray", "Türkiye", "Midtjylland", "Danimarka", "Rennes", "France", "Ferenevaros", "Macaristan");
List<Map<String, String>> remainingBags = new ArrayList<>();
remainingBags.add(bagTwo);
remainingBags.add(bagThree);
remainingBags.add(bagFour);
List<String> bagOneTeams = new ArrayList<String>(bagOne.keySet());
Collections.shuffle(bagOneTeams);
List<List<String>> remainingTeams = new ArrayList<>();
remainingTeams.add(new ArrayList<>(bagTwo.keySet()));
remainingTeams.add(new ArrayList<>(bagThree.keySet()));
remainingTeams.add(new ArrayList<>(bagFour.keySet()));
Collections.shuffle(remainingTeams.get(0));
Collections.shuffle(remainingTeams.get(1));
Collections.shuffle(remainingTeams.get(2));
List<LinkedHashMap<String, String>> resultingTeams = new ArrayList<>();
IntStream.range(0, 8).forEach(i-> {
LinkedHashMap<String, String> team = new LinkedHashMap<>();
team.put(bagOneTeams.get(i), bagOne.get(bagOneTeams.get(i)));
IntStream.range(0, 3).forEach(j -> {
String nextTeam = getNonDuplicateCountryTeam(remainingTeams.get(j), team.keySet(), remainingBags.get(j), team.values());
team.put(nextTeam, remainingBags.get(j).get(nextTeam));
});
resultingTeams.add(team);
});

How to convert a list of java objects to Map<String, Map<String, String>>

I have a list of java objects as below:
[
{
id: "frwfhfijvfhviufhbviufg",
country_code: "DE",
message_key: "key1",
translation: "This is the deutsch translation"
},
{
id: "dfregregtegetgetgttegt",
country_code: "GB",
message_key: "key1",
translation: "This is the uk translation"
},
{
id: "frffgfbgbgbgbgbgbgbgbg",
country_code: "DE",
message_key: "key2",
translation: "This is the again deutch translation"
}
]
How can I convert this into a Map<String, Map<String, String>> like below:
{
"DE": {
"key1": "This is the deutsch translation",
"key2": "This is the again deutch translation"
},
"GB": {
"key1": "This is the uk translation"
}
}
I am new to java and below is my code but the code is not correct:
Map<String, Translations> distinctTranslations = customTranslationsEntities
.stream().collect(Collectors.groupingBy(
CustomTranslationsEntity::getCountryCode,
Collectors.toMap(
CustomTranslationsEntity::getMessageKey,
CustomTranslationsEntity::getTranslation),
)))
where Translations is proto buffer message like below:
message Translations {
map<string, string> translations = 1;
}
Here map<string, string> translations means map like "key1", "This is the deutsch translation"...like this.
The output should be Map<String, Map<String,String>>:
Map<String, Map<String,String>>
distinctTranslations = customTranslationsEntities
.stream()
.collect(Collectors.groupingBy(CustomTranslationsEntity::getCountryCode,
Collectors.toMap(
CustomTranslationsEntity::getMessageKey,
CustomTranslationsEntity::getTranslation,
(v1,v2)->v1)));
I added a merge function, in case there are duplicate keys.
If you want to do it without using streams then
private List<MyObject> list = // Your object List
private Map<String, Map<String, String>> map = new HashMap<>();
for(MyObject object : list){
Map<String, String> localMap;
localMap = map.getOrDefault(object.country_code, new HashMap<>());
localMap.put(object.message_key, object.translation);
if(!map.containsKey(object.country_code)){
map.put(object.country_code, localMap);
}
}

Change Java Spring code from AggregationOutput to DBCollection Aggregation methods

I'm updating a 2014 Java project with the latest libraries and MongoDB Java Driver changed from 3.0 to 3.6. Most of the codes has been updated but there is a specific query pretty complicated which is giving me problems.
The Document is like this
{
"_id" : ObjectId("58750a67ae28bc28e0705b0f"),
"info": "description",
"parentId", "variable-id-here"
"issues": [
{"name": "a", "closed": true},
{"name": "b", "closed": false},
{"name": "c", "closed": true}
],
"bugs": [
{"name": "d", "closed": false},
{"name": "e", "closed": false},
{"name": "f", "closed": true}
],
"errors": [
{"name": "g", "closed": true},
{"name": "h", "closed": true},
{"name": "i", "closed": false}
]
}
(even if elements in arrays are similar, they can't be grouped in a single array in the document with an extra "type" key with values [issues, bugs, errors], but that's not the point)
The old script is this one
List<DBObject> aggregators = new ArrayList<>();
DBObject match = new BasicDBObject("$match", new BasicDBObject("parentId", myId));
DBObject project = new BasicDBObject();
List<String> domains = Arrays.asList("issues", "bugs", "errors");
for (Iterator<String> d = domains.iterator(); d.hasNext();) {
String domain = d.next();
//Reset values
aggregators = new ArrayList<>();
// Define MongoDB "$project" to find 'true' values on 'closed' flags
project = new BasicDBObject("$project", new BasicDBObject("closedProblems",
new BasicDBObject("$filter",
new BasicDBObject("input", "$"+domain)
.append("as", "myObject")
.append("cond", new BasicDBObject("$eq",
Arrays.<Object> asList("$$myObject.closed", true)
)
)
)
));
aggregators.add(match);
aggregators.add(project);
//db defined before. AggregationOutput is deprecated so must be changed
AggregationOutput output = db.getCollection("myColl").aggregate(aggregators);
// Now I can iterate results
for (DBObject result : output.results()) {
// ...
}
}
I tried to use projects, expressions, etc. but I can't find a way to duplicate the MongoDB project with new Aggregation methods.
The final result should use mongoTemplate.anyMethods to execute the Aggregation in order to join new project guidelines
Use below code in 3.6 driver.
DBCursor output = (DBCursor) db.getCollection("myColl").aggregate(aggregators, AggregationOptions.builder().build());
for (Iterator<DBObject> r = output.iterator(); output.hasNext();) {
DBObject result = r.next();
...
}
Update:
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
import static org.springframework.data.mongodb.core.aggregation.ArrayOperators.Filter.filter;
import static org.springframework.data.mongodb.core.aggregation.ComparisonOperators.Eq.valueOf;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.aggregation.*;
List<AggregationOperation> aggregators;
MatchOperation match = Aggregation.match(Criteria.where("parentId").is(myId));
List<String> domains = Arrays.asList("issues", "bugs", "errors");
for (Iterator<String> d = domains.iterator(); d.hasNext();) {
String domain = d.next();
aggregators = new ArrayList<>();
ProjectionOperation project = project().and(filter(domain)
.as("myObject")
.by(valueOf(
"myObject.closed")
.equalToValue(
true)))
.as("closedProblems");
aggregators.add(match);
aggregators.add(project);
Aggregation aggregation = newAggregation(aggregators).withOptions(newAggregationOptions().cursor(new Document()).build());
AggregationResults<Document> results = mongoTemplate.aggregate(aggregation, "myColl", Document.class );
for (Document result : results) {
// ...
}
}

How do i refactor one JSON array into other format in JAVA?

I have a JSON array like this,
JSONArray content=
"[
{"+"\"pageid\":\"19\","+"\"company\":"+"\"C1\","+"\"pageview\":"+"\"10\","+"\"visitfreq\":"+"\"2\"},{"+"\"pageid\":\"19\","+"\"company\":"+"\"C2\","+"\"pageview\":"+"\"20\","+"\"visitfreq\":"+"\"4\"},{"+"\"pageid\":\"200\","+"\"company\":"+"\"C3\","+"\"pageview\":"+"\"30\","+"\"visitfreq\":"+"\"3\"}
]";
Code for JSONArray:
JSONObject jObj1 = new JSONObject();
jObj1.put("pageid", "19");
jObj1.put("company", "C1");
jObj1.put("pageview", "10");
jObj1.put("visitfreq", "2");
JSONObject jObj2 = new JSONObject();
jObj2.put("pageid", "19");
jObj2.put("company", "C2");
jObj2.put("pageview", "20");
jObj2.put("visitfreq", "4");
JSONObject jObj3 = new JSONObject();
jObj3.put("pageid", "200");
jObj3.put("company", "C3");
jObj3.put("pageview", "30");
jObj3.put("visitfreq", "3");
JSONArray jArr = new JSONArray();
jArr.put(jObj1);
jArr.put(jObj2);
jArr.put(jObj3);
Visual representation:
[
{
"company": "C1",
"visitfreq": "2",
"pageview": "10",
"pageid": "19"
},
{
"company": "C2",
"visitfreq": "4",
"pageview": "20",
"pageid": "19"
},
{
"company": "C3",
"visitfreq": "3",
"pageview": "30",
"pageid": "200"
}
]
I have worked on it to get an out put like below
the out put like this
[{pageid},[{rest of details}] ,{pageid},[{rest of details}] ]
if same pageid occur more than once
it should be like this
[{pageid},[{rest of details1},{rest of details2},.. ],{pageid},[{rest of details}] ]
Looks like you need to create a Map that maps pageid : [{rest of details1},{rest of details2},.. ].
Once you have that Map, you can transform it into your desired output.
Here is the code that will take your JSONArray (the one in the code above) and turn it into Map<String, JSONArray>.
public Map<String, JSONArray> getJsonArrayAsMapOnPageId(JSONArray inputArr) throws JSONException {
//Map holding pageid : [{company:"",pageview:"",visitfreq:""}, ... , ...] mappings
Map<String, JSONArray> idMap = new HashMap<String, JSONArray>();
for (int i=0; i < inputArr.length(); i++) {
JSONObject inputObj = inputArr.getJSONObject(i);
String id = inputObj.getString("pageid");
JSONArray jObjList;
if (idMap.containsKey(id)) {
//append to existing list in the Map
jObjList = idMap.get(id);
} else {
//create new list
jObjList = new JSONArray();
}
JSONObject newJsonObj = new JSONObject();
newJsonObj.put("company", inputObj.get("company"));
newJsonObj.put("pageview", inputObj.get("pageview"));
newJsonObj.put("visitfreq", inputObj.get("visitfreq"));
jObjList.put(newJsonObj);
idMap.put(id, jObjList);
}
return idMap;
}
Here is what it'll look like:
System.out.println("Map looks like:\n" + pageidMap);
Here is what I got:
{
200=[
{
"company": "C3",
"visitfreq": "3",
"pageview": "30"
}
],
19=[
{
"company": "C1",
"visitfreq": "2",
"pageview": "10"
},
{
"company": "C2",
"visitfreq": "4",
"pageview": "20"
}
]
}
I'm not sure exactly in what form (Object, print to output, etc) you want this output to be in, so you can do the final bit of transforming this Map<String, JSONArray> into [{pageid},[{rest of details1},{rest of details2},.. ],{pageid},[{rest of details}] ] without problems.

Categories