[英]Modelling Complex Types for DynamoDB in Kotlin
我有一個需要讀/寫的 DynamoDB 表。 我正在嘗試創建一個 model 用於使用 Kotlin 從 DynamoDB 讀取和寫入。 但我一直遇到com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException: MyModelDB[myMap]; could not unconvert attribute
運行dynamoDBMapper.scanPage(...)
時com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMappingException: MyModelDB[myMap]; could not unconvert attribute
。 有時myMap
將改為MyListOfMaps
,但我猜這是通過迭代 Map 的鍵。
我的代碼如下:
@DynamoDBTable(tableName = "") // Non-issue, I am assigning the table name in the DynamoDBMapper
data class MyModelDB(
@DynamoDBHashKey(attributeName = "id")
var id: String,
@DynamoDBAttribute(attributeName = "myMap")
var myMap: MyMap,
@DynamoDBAttribute(attributeName = "MyListOfMapItems")
var myListOfMapItems: List<MyMapItem>,
) {
constructor() : this(id = "", myMap = MyMap(), myListOfMaps = mutableListOf())
@DynamoDBDocument
class MyMap {
@get:DynamoDBAttribute(attributeName = "myMapAttr")
var myMapAttr: MyMapAttr = MyMapAttr()
@DynamoDBDocument
class MyMapAttr {
@get:DynamoDBAttribute(attributeName = "stringValue")
var stringValue: String = ""
}
}
@DynamoDBDocument
class MyMapItem {
@get:DynamoDBAttribute(attributeName = "myMapItemAttr")
var myMapItemAttr: String = ""
}
}
我正在使用com.amazonaws:aws-java-sdk-dynamodb:1.11.500
package 並且我的dynamoDBMapper
是使用DynamoDBMapperConfig.Builder().build()
初始化的。
我的問題是我做錯了什么,為什么? 我還看到一些 Java 實現使用DynamoDBTypeConverter
。 它更好嗎,我應該改用它嗎?
任何例子將不勝感激!
這里有一些評論。 首先,您沒有將AWS SDK 用於 Kotlin 。 您正在使用另一個 SDK 並簡單地編寫 Kotlin 代碼。 使用此 SDK,您不會獲得 Kotlin 的全部好處,例如對協程的支持。
適用於 Kotlin(確實提供對 Kotlin 功能的完全支持)的 AWS SDK本周剛剛作為 DEV 預覽版發布。 請參閱開發指南:
然而這個 SDK 目前不支持這個映射。 要使用AWS SDK for Kotlin將項目放入 Amazon DynamoDB 表中,您需要使用:
mutableMapOf<String, AttributeValue>
To map Java Objects to a DynamoDB table, you should look at using the DynamoDbEnhancedClient that is part of AWS SDK for Java V2 . 有關Java V2 開發人員指南,請參閱 AWS SDK中的此主題:
您可以在AWS Github 存儲庫中找到使用增強型客戶端的其他示例。
好的,由於一些幫助,我最終得到了這個工作。 在得到更好的理解后,我稍微編輯了這個問題。 以下是我的數據 class 最終結果。 對於 Java 用戶,Kotlin 編譯為 Java,所以如果你能弄清楚轉換是如何工作的,那么想法應該也是一樣的。
data class MyModelDB(
@DynamoDBHashKey(attributeName = "id")
var id: String = "",
@DynamoDBAttribute(attributeName = "myMap")
@DynamoDBTypeConverted(converter = MapConverter::class)
var myMap: Map<String, AttributeValue> = mutableMapOf(),
@DynamoDBAttribute(attributeName = "myList")
@DynamoDBTypeConverted(converter = ListConverter::class)
var myList: List<AttributeItem> = mutableListOf(),
) {
constructor() : this(id = "", myMap = MyMap(), myList = mutableListOf())
}
class MapConverter : DynamoDBTypeConverter<AttributeValue, Map<String,AttributeValue>> {
override fun convert(map: Map<String,AttributeValue>>): AttributeValue {
return AttributeValue().withM(map)
}
override fun unconvert(itemMap: AttributeValue?): Map<String,AttributeValue>>? {
return itemMap?.m
}
}
class ListConverter : DynamoDBTypeConverter<AttributeValue, List<AttributeValue>> {
override fun convert(list: List<AttributeValue>): AttributeValue {
return AttributeValue().withL(list)
}
override fun unconvert(itemList: AttributeValue?): List<AttributeValue>? {
return itemList?.l
}
}
這至少可以讓我使用我的自定義轉換器將我的數據從 DynamoDB 中取出。 我會在 go 上定義一個單獨的數據容器 class 以在我自己的應用程序中使用,並且我創建了一個在這兩個數據對象之間進行序列化和反序列化的方法。 這更像是您希望如何處理數據的偏好,但這對我來說就是這樣。
// For reading and writing to DynamoDB
class MyModelDB {
...
fun toMyModel(): MyModel {
...
}
}
// For use in my application
class MyModel {
var id: String = ""
var myMap: CustomObject = CustomObject()
var myList<CustomObject2> = mutableListOf()
fun toMyModelDB():MyModelDB {
...
}
}
最后,我們來實現 2 個toMyModel.*()
方法。 讓我們從輸入開始,這就是我的列的樣子:
我的地圖:
{
"key1": {
"M": {
"subKey1": {
"S": "some"
},
"subKey2": {
"S": "string"
}
}
},
"key2": {
"M": {
"subKey1": {
"S": "other"
},
"subKey2": {
"S": "string"
}
}
}
}
我的清單:
[
{
"M": {
"key1": {
"S": "some"
},
"key2": {
"S": "string"
}
}
},
{
"M": {
"key1": {
"S": "some string"
},
"key3": {
"M": {
"key4": {
"S": "some string"
}
}
}
}
}
]
然后訣竅是使用com.amazonaws.services.dynamodbv2.model.AttributeValue
來轉換 JSON 中的每個字段。 因此,如果我想訪問subKey2
的key1
字段中myMap
的值,我會這樣做:
myModelDB.myMap["key1"]
?.m // Null check and get the value of key1, a map
?.get("subKey2") // Get the AttributeValue associated with the "subKey2" key
?.s // Get the value of "subKey2" as a String
這同樣適用於myList
:
myModelDB.myList.foreach {
it?.m // Null check and get the map at the current index
?.get("key1") // Get the AttributeValue associated with the "key1"
...
}
編輯:懷疑這將是一個很大的問題,但我還將我的 DynamoDB 依賴項更新為com.amazonaws:aws-java-sdk-dynamodb:1.12.126
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.