[英]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.