DynamoDB值得二进制数据

发布于 2025-02-11 06:28:00 字数 2446 浏览 2 评论 0原文

即时通讯使用以下代码对DynamoDB数据进行估算。

class DecimalEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, set):
            return list(o)
        if isinstance(o, decimal.Decimal):
            if o % 1 > 0:
                return float(o)
            else:
                return int(o)
        if isinstance(o, bytes):
            return b64encode(o).decode()        
        return super(DecimalEncoder, self).default(o)


def from_dynamodb_to_json(item):
    return {k: TypeDeserializer().deserialize(value=v) for k, v in item.items()}

## code to convert
base64.b64encode((json.dumps(from_dynamodb_to_json(payload["dynamodb"]["NewImage"]), cls=DecimalEncoder) + '\n').encode("utf-8")).decode("utf-8")

但是它给出以下错误。

[ERROR] TypeError: Value must be of the following types: <class 'bytearray'>, <class 'bytes'>.
Traceback (most recent call last):
  File "/var/task/lambda_function.py", line 60, in lambda_handler
    'data': base64.b64encode((json.dumps(from_dynamodb_to_json(payload["dynamodb"]["NewImage"]), cls=DecimalEncoder) + '\n').encode("utf-8")).decode("utf-8")
  File "/var/task/lambda_function.py", line 33, in from_dynamodb_to_json
    return {k: TypeDeserializer().deserialize(value=v) for k, v in item.items()}
  File "/var/task/lambda_function.py", line 33, in <dictcomp>
    return {k: TypeDeserializer().deserialize(value=v) for k, v in item.items()}
  File "/var/runtime/boto3/dynamodb/types.py", line 271, in deserialize
    return deserializer(value[dynamodb_type])
  File "/var/runtime/boto3/dynamodb/types.py", line 286, in _deserialize_b
    return Binary(value)
  File "/var/runtime/boto3/dynamodb/types.py", line 51, in __init__
    ', '.join([str(t) for t in BINARY_TYPES]))

有效载荷中的示例数据

{'awsRegion': 'ap-south-1', 'eventID': 'd926b17c-33a7-4d05-b936-7f5d9cd36a52', 'eventName': 'INSERT', 'userIdentity': None, 'recordFormat': 'application/json', 'tableName': 'dev_bhuvi_de', 'dynamodb': {'ApproximateCreationDateTime': 1656405526550, 'Keys': {'id': {'N': '261'}}, 'NewImage': {'id': {'N': '261'}, 'NewValue': {'B': 'YkdsdWRYaG9hVzUwTG1OdmJRbz0='}}, 'SizeBytes': 32}, 'eventSource': 'aws:dynamodb'}

Im using the following code to deserialize the dynamoDB data.

class DecimalEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, set):
            return list(o)
        if isinstance(o, decimal.Decimal):
            if o % 1 > 0:
                return float(o)
            else:
                return int(o)
        if isinstance(o, bytes):
            return b64encode(o).decode()        
        return super(DecimalEncoder, self).default(o)


def from_dynamodb_to_json(item):
    return {k: TypeDeserializer().deserialize(value=v) for k, v in item.items()}

## code to convert
base64.b64encode((json.dumps(from_dynamodb_to_json(payload["dynamodb"]["NewImage"]), cls=DecimalEncoder) + '\n').encode("utf-8")).decode("utf-8")

But it gives the following error.

[ERROR] TypeError: Value must be of the following types: <class 'bytearray'>, <class 'bytes'>.
Traceback (most recent call last):
  File "/var/task/lambda_function.py", line 60, in lambda_handler
    'data': base64.b64encode((json.dumps(from_dynamodb_to_json(payload["dynamodb"]["NewImage"]), cls=DecimalEncoder) + '\n').encode("utf-8")).decode("utf-8")
  File "/var/task/lambda_function.py", line 33, in from_dynamodb_to_json
    return {k: TypeDeserializer().deserialize(value=v) for k, v in item.items()}
  File "/var/task/lambda_function.py", line 33, in <dictcomp>
    return {k: TypeDeserializer().deserialize(value=v) for k, v in item.items()}
  File "/var/runtime/boto3/dynamodb/types.py", line 271, in deserialize
    return deserializer(value[dynamodb_type])
  File "/var/runtime/boto3/dynamodb/types.py", line 286, in _deserialize_b
    return Binary(value)
  File "/var/runtime/boto3/dynamodb/types.py", line 51, in __init__
    ', '.join([str(t) for t in BINARY_TYPES]))

Sample data in payload

{'awsRegion': 'ap-south-1', 'eventID': 'd926b17c-33a7-4d05-b936-7f5d9cd36a52', 'eventName': 'INSERT', 'userIdentity': None, 'recordFormat': 'application/json', 'tableName': 'dev_bhuvi_de', 'dynamodb': {'ApproximateCreationDateTime': 1656405526550, 'Keys': {'id': {'N': '261'}}, 'NewImage': {'id': {'N': '261'}, 'NewValue': {'B': 'YkdsdWRYaG9hVzUwTG1OdmJRbz0='}}, 'SizeBytes': 32}, 'eventSource': 'aws:dynamodb'}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

挖个坑埋了你 2025-02-18 06:28:01

当尝试从python lambda中的dynamoDB流解析数据时,我遇到了同一问题。

问题是,当发生DynamoDB更改时,发送给Lambda处理程序的事件字典具有所有二进制类型base64 base64编码。您的解决方案朝着正确的方向前进。

请参阅下面添加的有关如何解决此问题的__ deserialize()方法:

import base64
from boto3.dynamodb.types import TypeDeserializer

lambda_event = {
    'awsRegion': 'us-east-0',
    'eventID': 'd926b17c-33a7-4d05-b936-7f5d9cd36a52',
    'eventName': 'INSERT',
    'userIdentity': None,
    'recordFormat': 'application/json',
    'tableName': 'my_table_name',
    'dynamodb': {
        'ApproximateCreationDateTime': 1656405526550,
        'Keys': {'id': {'N': '261'}},
        'NewImage': {'id': {'N': '261'}, 'NewValue': {'B': 'YkdsdWRYaG9hVzUwTG1OdmJRbz0='}},
        'SizeBytes': 32
    },
    'eventSource': 'aws:dynamodb'
}

def from_dynamodb_to_json(item):
    return {k: __deserialize(value=v) for k, v in item.items()}

def __deserialize(value):
    dynamodb_type = list(value.keys())[0]

    # DynamoDb stream base64-encodes all binary types, must base64 decode first
    if dynamodb_type == "B" and isinstance(value["B"], str):
        value = {"B": base64.b64decode(value["B"])}

    return TypeDeserializer().deserialize(value)

result = from_dynamodb_to_json(lambda_event["dynamodb"]["NewImage"])
print(result)

I ran across the same issue when trying to parse data from a dynamodb stream from within a python lambda.

The issue is that when a dynamodb change occurs, the event dictionary that is sent to the lambda handler has all binary types base64 encoded. Your solution is headed in the right direction.

Please see the __deserialize() method I added below for how to solve this issue:

import base64
from boto3.dynamodb.types import TypeDeserializer

lambda_event = {
    'awsRegion': 'us-east-0',
    'eventID': 'd926b17c-33a7-4d05-b936-7f5d9cd36a52',
    'eventName': 'INSERT',
    'userIdentity': None,
    'recordFormat': 'application/json',
    'tableName': 'my_table_name',
    'dynamodb': {
        'ApproximateCreationDateTime': 1656405526550,
        'Keys': {'id': {'N': '261'}},
        'NewImage': {'id': {'N': '261'}, 'NewValue': {'B': 'YkdsdWRYaG9hVzUwTG1OdmJRbz0='}},
        'SizeBytes': 32
    },
    'eventSource': 'aws:dynamodb'
}

def from_dynamodb_to_json(item):
    return {k: __deserialize(value=v) for k, v in item.items()}

def __deserialize(value):
    dynamodb_type = list(value.keys())[0]

    # DynamoDb stream base64-encodes all binary types, must base64 decode first
    if dynamodb_type == "B" and isinstance(value["B"], str):
        value = {"B": base64.b64decode(value["B"])}

    return TypeDeserializer().deserialize(value)

result = from_dynamodb_to_json(lambda_event["dynamodb"]["NewImage"])
print(result)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文