Map attributes not updated properly in Dynamo. New field is added instead. - java

I am using the AWS Java SDK for communicating with DynamoDB. I am trying to do a table update of some properties stored in a map.
Before the update, I have an object that looks like this:
{
"myMap": {
"innerMap": {}
},
"hashKeyName": "hashKeyValue"
}
My code looks like this:
Table myTable = ...;
myTable.updateItem("hashKeyName", "hashKeyValue",
new AttributeUpdate("myMap.innerMap.myKey").addNumeric(100));
After this update, my Dynamo object looks like this (notice that the map is still empty):
{
"myMap": {
"innerMap": {}
},
"myMap.innerMap.myKey": 100,
"hashKeyName": "hashKeyValue"
}
Why was myMap.innerMap.myKey added as a separate field instead of being correctly set in the map?

The reason for this is because using AttributeUpdate is considered a legacy operation and the usage of map keys as attribute names is not supported. The correct usage to use an update expression:
myTable.updateItem("hashKeyName", "hashKeyValue",
"ADD myMap.innerMap.myKey :val", null /* NameMap, see comment */,
new ValueMap().withNumeric(":val", 100));
Notice that there is no name map in the above expression. One might be tempted to do use ADD #name :val as an update expression and then provide a name map for #name => myMap.innerMap.myKey. In this case, these expressions are not equivalent. When a . appears in the raw expression, it is treated as a path separator. When . appears in a NameMap value, it is not considered a path separator.

Related

jOOQ select with map type values

There is a table that has map type column, and the map column type would be like below
Map<String, CustomClass.class>
and CustomClass is like below
Class CustomClass {
String name;
String attr;
}
I would like to select record that match 'keyword' contain in map column's values (no matter what key is). I need something like below. Is there any way that I can use?
JooqQuery jooqQuery = (SelectJoinStep<?> step) -> {
step.where(MANAGERS.NAME_DESC_I18N_MAP.contains(
Map<"ANY KEY", keyword in CustomClass.name> // need help here
));
You can use LIKE as a quantified comparison predicate in jOOQ. If it's not supported natively by your RDBMS, jOOQ will emulate it for you. Try this:
MANAGERS.NAME_DESC_I18N_MAP.like(any(
map.values().stream().map(cc -> "%" + cc.name + "%").toArray(String[]::new)
))
You can't use contains() in this way yet, but I guess that's OK.
See also this blog post about using LIKE as a quantified comparison predicate.

Case When or iif syntax expression in jooq

I am trying to reproduce this MySQL query in jooq.
messageTable1, messageTable2 same column
select
msg.index as index,
left(msg.message, if(msg.type = 1, 10, msg.maxLength)) as message
from
messageTable1 as msg
select
msg.index as index,
left(msg.message, if(msg.type = 1, 10, msg.maxLength)) as message
from
messageTable2 as msg
making function java
public Message getMessageTest(String tableName) {
return roDslContext.select(
DSL.field("msg.index").as("index"),
left(DSL.field( "{0}", String.class, "msg.message"),
when(DSL.field("msg.type").eq(1), 10, DSL.field( "{0}", String.class, "msg.maxLength").as("message)
.from(tableName)
.fetchOneInto(Message.class);
}
but....
when(DSL.field("msg.type").eq(1), 10, DSL.field( "{0}", String.class, "msg.maxLength").as("message)
jooq is field msg.maxLength ... not accept
also so iif
how case, when, iif insert field column data??
Using the code generator
I'm assuming you're not using the code generator in this example, because you want to make your column references dynamic, depending on the table name.
There's a possibility of generating common interfaces onto your tables, which would abstract over the two table types. Also, there are Table.rename(String) methods generated on those tables, which allow for renaming a table MESSAGE_TABLE_1.rename("message_table_2"). So your query would look like this:
public Message getMessageTest(String tableName) {
MessageTable1 msg = MESSAGE_TABLE_1.rename(tableName);
return roDslContext
.select(
msg.INDEX,
left(msg.MESSAGE, if_(msg.TYPE.eq(1), val(10), msg.MAX_LENGTH))
)
.from(msg)
.fetchOneInto(Message.class);
}
As always, this is assuming the following static import:
import static org.jooq.impl.DSL.*;
The actual problem
You seem to be attempting to construct field references using plain SQL templating. You did it right for msg.index via DSL.field("msg.index"), but somehow tripped over the templating syntax for msg.message. This doesn't make sense:
field("{0}", String.class, "msg.message");
When using a template, the placeholder {0} needs to be replaced by a QueryPart instance. You can't just pass a String instead (which would be interpreted as a bind value). What you meant to do here is any of these:
// If you really need templating, though here, you don't:
field("{0}", String.class, name("msg", "message"));
// Instead, just do this, if you want quoted names:
field(name("msg", "message"), String.class);
// Or this, if you don't care about quoting the name
field("msg.message", String.class);

How do I update many attributes in DynamoDB

I've seen a lot of examples of using UpdateExpression to update attributes using the updateItem method. However, I still don't understand how to update multiple attributes in DynamoDB at the same time dynamically.
I am trying to update AND rename multiple attributes in the same updateItem call.
I understand that this requires a REMOVE of the old name and a SET of the new name. I have these names in hashedId's of objects, but won't have them until runtime. So my question is how do I use UpdateExpression with variables and not a hard-coded String?
All the examples I have seen use hard-coded UpdateExpressions.
can't update item in DynamoDB
Dynamo DB : UpdateItemSpec : Multiple Update Expression - Not Working
DynamoDB update Item multi action
How to rename DynamoDB column/key
I am working in Java.
It seems very odd to me that I haven't been able to find an example of this... which leads me to believe I am doing something wrong.
Thanks for the help!
You have to build the update expression string dynamically based on the attribute names and values that you receive at runtime. I do exactly this. I'm not working in Java, but here is some pseudo code (with a Ruby bias) example for you that dynamically builds the update expression string, the expression attribute names hash, and the expression attribute values hash. You can then plug in these 3 things into the update_item method:
update_exp_set = [] //array of remove expression snippets
update_exp_remove = [] //array of update expression snippets
exp_attribute_names = {} //hash of attribute names
exp_attribute_values = {} //hash of attribute values
// Iterate through all your fields and add things as needed to your arrays and hashes.
// Two examples are below for a field with the name <fieldName> and value <fieldValue>.
// You'll need to convert this to Java and update it to make sense with the AWS Java SDK.
// For a given field that needs to be updated:
update_exp_set << "#<fieldName> = :fieldValue" //add to array of set expression snippets
exp_attribute_names["#<fieldName>"] = "<fieldName>" //add to hash of attribute names
exp_attribute_values[":<fieldValue>"] = "<fieldValue>" //add to hash of attribute values
// For a given field that needs to be removed:
update_exp_remove << "#<fieldName>"
exp_attribute_names["#<fieldName>"] = "<fieldName>" //add to hash of attribute names
// Use your snippets to create your full update expression:
update_exp_set_clause = ""
update_exp_remove_clause = ""
if update_exp_set.length != 0 //check if you have something to set
update_exp_set_clause = "SET " + update_exp_set.join(',')
end
if update_exp_remove.length != 0 //check if you have something to remove
update_exp_remove_clause = "REMOVE" + update_exp_remove.join(',')
end
final_update_exp = update_exp_set_clause + " " + update_exp_remove_clause
Does this help?

How to query Grakn with Java?

I went through the documentation of Java api to query Grakn database.
Grakn.Transaction readTransaction = session.transaction(GraknTxType.READ);
GetQuery query = Graql.match(var("p").isa("person")).limit(10).get();
Stream<ConceptMap> answers = query.withTx(readTransaction).stream();
answers.forEach(answer -> System.out.println(answer.get("p").id()));
It's printing id, but I want to see the data, the name associated with the person. I want to see the content inside the result. It's simply showing id.
The answers provided as the result of a Graql query, is a collection of the variables (and their values) as you have specified them in the query itself.
In this case, to get the name of instances of person, you'd include it in the query like so:
GetQuery query = Graql.match(var("p").isa("person").has("name", var("n"))).limit(10).get();
The Graql equivalent being match $p isa person, has name $n; get;.
Now you can use the methods available in the Concept API to retrieve information available on each variable.
In this case, variable n holds an attribute and you'd want to retrieve its value(), like so:
answers.forEach(answer -> System.out.println(answer.get("n").asAttribute().value()))

how can I get dynamic property in drools

I have a XML file containing metadata like a field's maximum length. I have to use drools to build rules to validate this metadata against a list of facts. I don't want to hardcode the name of each field that may or may not be specified in the XML.
I tried to do this :
when
$metadata: Metadata(maxLength != null);
$obj: Object(eval($metadata.getFieldName()).length > $metadata.maxLength);
then
// TODO
end
It does not work and I get the following error :
java.lang.IllegalStateException: Errors while building rules : Unable
to Analyse Expression $metadata.getFieldName() > $metadata.maxLength:
[Error: Comparison operation requires compatible types. Found class
java.lang.String and class java.lang.Integer] [Near : {...
$metadata.getFieldName() > $metadata.maxLength ....}]
Is it possible to dynamically get a field name and compare its maximum length? Will I have to create a java object to accomplish this?
Thank you
You talk of XML and metadata. Can you distinguish all entities? For example, if it is about orders, can you extract each order, and attributes of each order?
I solved a similar problem with using maps to store each attribute.
public class Order{
private int id;
private Map<String, Integer> num_attribute_map = new HashMap<String, Integer>();
public Map getNumAttributeMap(){
return this.num_attribute_map;
}
If an order has customer_satisfaction = 5,
order_obj.getNumAttributeMap().put("customer_satisfaction" , 5);
And thus you have created Orders with their attributes stored in the numAttributeMap.
For implementing a rule on an Order
$ord : Order(
getNumAttributeMap[$attribute] >= $value
)
where $attribute would be "customer_satisfaction", of course. The [] notation is used to access elements of a list, given index or values of a map, given the key.
Hope you "get" the concepts of maps. Also, do look up Drools language support for list and map access.
I have also implemented maps of lists of strings to perform an "is in" operation, in addition to maps of integers that do comparison operations. Please refer https://stackoverflow.com/a/9241089/604511 too
Finally, I have decided to generate my drools file dynamically from my XML using rule templates.

Categories

Resources