How to use IN statement in partiqL DynamodB - amazon-dynamodb

I want to convert this query
select lKey from KeyMapping where gKey in ['A#1','A#2','A#3'];
I have a List that contain A#1, A#2 and A#3
into Java code to extract records from DynamoDB using PartiQL

#Autowired
private AmazonDynamoDB client;
List<String> paramList = new ArrayList<>(); //List of Parameters
paramList.add("A#1");
paramList.add("A#2");
paramList.add("A#3");
ExecuteStatementRequest request = new ExecuteStatementRequest();
String[] placeholders = new String[paramList.size()];
Arrays.fill(placeholders, "?");
String commalist = Arrays.stream(placeholders).collect(Collectors.joining(","));
request.setStatement("select * from "+appConfigs.getBoclipsTableName()+" where id in ("+commalist+")");
List<AttributeValue> parameters = new ArrayList<>();
for(String videoId: videoIds){
parameters.add(new AttributeValue(videoId));
}
System.out.println(client.executeStatement(request).toString());

Related

How to read data from CosmosDb when i only have the partitionkey but not the id of the document

When trying to read from CosmosDb i can select a document via:
Id Query
Id + PartitionKey Query
but how do i select data from CosmosDb when i only have the PartitionKey?
using Microsoft.Azure.Cosmos;
public class CosmosDbService : ICosmosDbService
{
private Container _container;
public CosmosDbService(
CosmosClient cosmosDbClient,
string databaseName,
string containerName)
{
_container = cosmosDbClient.GetContainer(databaseName, containerName);
}
public async Task<Error> GetItemAsync(string partitionKey)
{
// selection only via partitionKey - does not work
var response = await _container.ReadItemAsync<Error>(partitionKey, new PartitionKey(partitionKey));
return response.Resource;
// below one works as i am passing the Id (internally generated by CosmosDB)
var id = "2e4e5727-86ff-4c67-84a6-184b4716d744";
var response = await _container.ReadItemAsync<Error>(id, new PartitionKey(partitionKey));
return response.Resource;
}
}
Question:
Are there any other methods in CosmosDB client which can return the document using the PartitionKey ONLY without the need of Id which I don't know ?
When selecting documents you could try to use QueryDefinition + QueryAsync:
var query = new QueryDefinition("select top 1 * from c");
var partitionKey = "PARTITIONKEY";
var resultSet = container.GetItemQueryIterator<ModelObject>(query, null, new QueryRequestOptions { PartitionKey = new PartitionKey(partitionKey) });
var result = new List<ModelObject>();
while (resultSet.HasMoreResults)
{
var item = await resultSet.ReadNextAsync(ct /* CancellationToken */).ConfigureAwait(false);
var itemList = item.ToList();
result.AddRange(itemList);
}
Instead of a top 1 select you could also do a select * (for example)

DynamoDB ItemCollection<QueryOutcome> to java object

I want to convert ItemCollection into my java pojo object .I want currently doing so by following way .What is the best way to do so?
QuerySpec spec = new QuerySpec()
.withKeyConditionExpression("txn_id = :txnId")
.withFilterExpression("rrn = :rrn")
.withValueMap(new ValueMap()
.withString(":txnId", txnId)
.withString(":rrn", rrn))
.withConsistentRead(true);
ItemCollection<QueryOutcome> items = table.query(spec);
here i got ItemCollection .Now i will be converting it to my java pojo :-
Iterator<Item> iter = items.iterator();
while (iter.hasNext()) {
String txn = iter.next().toJSON();
Gson gson = new Gson();
Test t = gson.fromJson(txn, Test.class);
return t;
}
Is there a way to convert dynamodb fetch value( ItemCollection) to java pojo directly like we do in mysql ?Why i will always get json then covert to pojo .We don't do so in other DB like mysql or oracle DB .
Text.java
public class Test implements Serializable {
#DynamoDBAttribute(attributeName = "txn_id")
#JsonProperty("txn_id")
#DynamoDBHashKey
private String txnId;
private String umn;
private String note;
#DynamoDBAttribute(attributeName = "rrn")
private String rrn;
#DynamoDBAttribute(attributeName = "expire_on")
private Date expireOn;
#DynamoDBAttribute(attributeName = "expire_after")
private Integer expireAfter;
#DynamoDBAttribute(attributeName = "created_on")
#DynamoDBAutoGeneratedTimestamp(strategy= DynamoDBAutoGenerateStrategy.CREATE)
private Date createdOn;
}
Yes, take a look at DynamoDBMapper. Uses the same pojo annotations...
CatalogItem partitionKey = new CatalogItem();
partitionKey.setId(102);
DynamoDBQueryExpression<CatalogItem> queryExpression = new DynamoDBQueryExpression<CatalogItem>()
.withHashKeyValues(partitionKey);
List<CatalogItem> itemList = mapper.query(CatalogItem.class, queryExpression);
for (int i = 0; i < itemList.size(); i++) {
System.out.println(itemList.get(i).getTitle());
System.out.println(itemList.get(i).getBookAuthors());
}

What is the alternative for AmazonDynamoDBClient that got deprecated?

Does anyone know what has replaced AmazonDynamoDBClient?
Couldn't find anything in the documentation
Package - com.amazonaws.services.dynamodbv2
AmazonDynamoDBClient amazonDynamoDBClient = new AmazonDynamoDBClient();
As per the API doc, the builder class (e.g. AmazonDynamoDBClientBuilder) should be used to create the instance.
Sample code using the builder class:-
I have create the client for DynamoDB local.
DynamoDB dynamoDB = new DynamoDB(AmazonDynamoDBClientBuilder.standard().withEndpointConfiguration(new EndpointConfiguration("http://localhost:8000", "us-east-1")).build());
Table table = dynamoDB.getTable("Movies");
Scan using DynamoDB table class:-
private static void findProductsForPriceLessThanZero() {
Table table = dynamoDB.getTable(tableName);
Map<String, Object> expressionAttributeValues = new HashMap<String, Object>();
expressionAttributeValues.put(":pr", 100);
ItemCollection<ScanOutcome> items = table.scan(
"Price < :pr", //FilterExpression
"Id, Title, ProductCategory, Price", //ProjectionExpression
null, //ExpressionAttributeNames - not used in this example
expressionAttributeValues);
System.out.println("Scan of " + tableName + " for items with a price less than 100.");
Iterator<Item> iterator = items.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next().toJSONPretty());
}
}
I am using spring-boot, the way I am working with Dynamo is injecting an AWSCredentialsProvider and using the variables which are in my environment in this way:
#Bean
public AmazonDynamoDB amazonDynamoDB(AWSCredentialsProvider awsCredentialsProvider) {
AmazonDynamoDB amazonDynamoDB
= AmazonDynamoDBClientBuilder.standard()
.withCredentials(awsCredentialsProvider).build();
return amazonDynamoDB;
}
#Bean
public AWSCredentialsProvider awsCredentialsProvider() {
return new EnvironmentVariableCredentialsProvider();
}
The full example is available here: https://github.com/ioet/bpm-skills-api

.net Querying a Global Secondary Index in DynamoDB via DynamoDBContext

I have a dynamoDB table with a schema as follows:
var request = new CreateTableRequest
{
TableName = tableName,
KeySchema = new List<KeySchemaElement>
{
new KeySchemaElement("CompanyId", KeyType.HASH),
new KeySchemaElement("Timestamp", KeyType.RANGE)
},
AttributeDefinitions = new List<AttributeDefinition>
{
new AttributeDefinition("CompanyId", ScalarAttributeType.S),
new AttributeDefinition("Timestamp", ScalarAttributeType.N),
new AttributeDefinition("UserId", ScalarAttributeType.S)
},
GlobalSecondaryIndexes = new List<GlobalSecondaryIndex>
{
new GlobalSecondaryIndex
{
IndexName = "UserIndex",
KeySchema = new List<KeySchemaElement>
{
new KeySchemaElement("UserId", KeyType.HASH),
new KeySchemaElement("Timestamp", KeyType.RANGE)
},
Projection = new Projection {ProjectionType = "ALL"},
ProvisionedThroughput = new ProvisionedThroughput(5, 6)
}
},
ProvisionedThroughput = new ProvisionedThroughput(5, 6)
};
I can query the primary key successfully as follows:
var client = new AmazonDynamoDBClient();
using (var context = new DynamoDBContext(client))
{
var sortKeyValues = new List<object>{minTimestamp};
result = await context.QueryAsync<AuditLogEntry>(companyId, QueryOperator.GreaterThanOrEqual, sortKeyValues,
new DynamoDBOperationConfig {OverrideTableName = TableName}).GetRemainingAsync();
}
And I can query the global secondary index without any constraint on the range key as follows:
var client = new AmazonDynamoDBClient();
using (var context = new DynamoDBContext(client))
{
result = await context.QueryAsync<AuditLogEntry>(userId, new DynamoDBOperationConfig {OverrideTableName = TableName, IndexName = indexName})
.GetRemainingAsync();
}
But when I try to query the index with a range key constraint:
var client = new AmazonDynamoDBClient();
using (var context = new DynamoDBContext(client))
{
var sortKeyValues = new List<object> {minTimestamp};
result = await context.QueryAsync<AuditLogEntry>(userId, QueryOperator.GreaterThan, sortKeyValues, new DynamoDBOperationConfig {OverrideTableName = TableName, IndexName = indexName}).GetRemainingAsync();
}
I get the following error:
Exception thrown: 'System.InvalidOperationException' in AWSSDK.DynamoDBv2.dll
Additional information: Local Secondary Index range key conditions are used but no index could be inferred from model. Specified index name = UserIndex
Googling this error hasn't thrown any light on the issue. The reference to Local Secondary Index has me confused because I'm using a Global index, but I just can't see what's wrong with my code.
I've been able to get the query working by querying directly on the AmazonDynamoDBClient rather than using DynamoDBContext, but I'd really like to understand what I'm doing wrong and be able to use DynamoDBContext.
Any ideas would be appreciated.
In your model definition for AuditLogEntry you need to decorate properties that are part of the global secondary index with attributes - [DynamoDBGlobalSecondaryIndexRangeKey] and or [DynamoDBGlobalSecondaryIndexHashKey]. Example below.
public class AuditLogEntry {
// other properties ...
[DynamoDBProperty("UserId")]
[DynamoDBGlobalSecondaryIndexHashKey("UserIndex")]
public string UserId { get; set; }
}

Can't fill Table with items with javafx

I'm not so good at javafx and also in English^^. I programmed a TableView but I don't know why it doesn't fill the Table with the Items I created. Perhaps it fills the Table, but I don't see them. I hope somebody could help me here out. Here is the Code:
private final TableView<VerzeichnisDaten> table = new TableView();
private final ObservableList<VerzeichnisDaten> data = FXCollections.observableArrayList();
TableColumn titleCol = new TableColumn("Titel");
TableColumn lastNameCol = new TableColumn("Nachname");
TableColumn firstNameCol = new TableColumn("Vorname");
TableColumn TelCol = new TableColumn("Telefon");
TableColumn FaxCol = new TableColumn("Fax");
TableColumn EmailCol = new TableColumn("E-Mail");
// here is a loop which wait for a mouse click on an item
// item will be saved in abteilung
try {
VD.mitarbeiter(abteilung);
} catch (SQLException ex) {
/* exception */);
}
centerPane.getChildren().clear();
table.getColumns().clear();
data.clear();
for(int j = 0;j < VD.count_mi;j++) {
data.add(new VerzeichnisDaten(VD.title_speicher[j], VD.lname_speicher[j], VD.fname_speicher[j], VD.tel_speicher[j], VD.fax_speicher[j],VD.email_speicher[j] ));
}
titleCol.setMinWidth(100);
titleCol.setCellValueFactory (new PropertyValueFactory<VerzeichnisDaten, String>("Titel"));
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory (new PropertyValueFactory<VerzeichnisDaten, String>("Nachname"));
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory (new PropertyValueFactory<VerzeichnisDaten, String>("Vorname"));
TelCol.setMinWidth(100);
TelCol.setCellValueFactory (new PropertyValueFactory<VerzeichnisDaten, String>("Telefon"));
FaxCol.setMinWidth(100);
FaxCol.setCellValueFactory (new PropertyValueFactory<VerzeichnisDaten, String>("Fax"));
EmailCol.setMinWidth(100);
EmailCol.setCellValueFactory (new PropertyValueFactory<VerzeichnisDaten, String>("E-Mail"));
table.setItems(data);
table.getColumns().addAll(titleCol,lastNameCol,firstNameCol,TelCol,FaxCol,EmailCol);
centerPane.getChildren().addAll(table);
mainPane.setCenter(centerPane);
}
primaryStage.setScene(new Scene(mainPane, 855, 400));
primaryStage.show();
Here is the Class VerzeichnisDaten:
String[] title_speicher, lname_speicher, fname_speicher, tel_speicher, fax_speicher, email_speicher;
SimpleStringProperty title, lastName, firstName, Tel, Fax, Email;
public VerzeichnisDaten (String title, String lname, String fname, String tel, String fax, String email) {
this.title = new SimpleStringProperty(title);
this.lastName = new SimpleStringProperty(lname);
this.firstName = new SimpleStringProperty(fname);
this.Tel = new SimpleStringProperty(tel);
this.Fax = new SimpleStringProperty(fax);
this.Email = new SimpleStringProperty(email);
}
// Setter and Getter are now implemented, only not shown
this code belongs to VerzeichnisDaten. above them was more code but is
not relevant now.
void mitarbeiter (String Abteilung) throws SQLException {
// more code ...
stmt = conn.createStatement();
rset = stmt.executeQuery(sql_mi_stmt);
i = 0;
while (rset.next()){
title_speicher[i] = rset.getString("title");
lname_speicher[i] = rset.getString("lname");
fname_speicher[i] = rset.getString("fname");
tel_speicher[i] = rset.getString("tel");
fax_speicher[i] = rset.getString("fax");
email_speicher[i] = rset.getString("email");
i = i + 1;
}
stmt.close();
}
The string that you supply to the PropertyValueFactory, e.g. as here:
new PropertyValueFactory<VerzeichnisDaten, String>("Titel")
must match the variable name of the property in your data class.
That is, if you have:
class Person {
StringProperty firstNameProperty; // note: must end in "Property", per convention
StringProperty lastNameProperty;
}
the respective property value factories would be:
new PropertyValueFactory<Person, String>("firstName") // property name sans "Property" postfix
new PropertyValueFactory<Person, String>("lastName")
In your code, you 1) have property names that do not end with "Property", i.e. you have:
SimpleStringProperty title, lastName, firstName, Tel, Fax, Email;
and 2) you have used the names of the columns headers instead of the property names in your property value factories.
And thus you have discovered the joys of string-based, or type-unsafe in general, programming: the compiler is happy, but nothing works.
The PropertyValueFactory supplied with JavaFX is at best a hack, and more generally a bad practice. If you look at its Javadoc, you see exactly what it does: it provides a simpler way of creating a value factory instead of having to deal with the ugly Callback SAM, by using reflection and special naming conventions (the latter to which you were victim) to find the right property value.
With Java 8's lambda syntax you can write those value factories in a much simpler way and I would disadvice the usage of PropertyValueFactory.

Resources