node.jsamazon-dynamodbaws-sdkdynamoose

How to instantiate Dynamoose Model from DynamoDB's AttributeValue format?


I am using Dynamodb streams to do some work on records as they are added or modified to my table. I am also using Dynamoose models in my application.

The Dynamodb stream event passes an event object to my node.js lambda handler that includes the objects record.dynamoDb.NewImage and record.dynamoDb.OldImage. However, these objects are in DynamoDB's AttributeValue format including all of the data types ('S' for string), rather than a normal javascript object. So record.id becomes record.id.S.

Dynamoose models allow you to instantiate a model from an object, like so: new Model(object). However, it expects that argument to be a normal object.

I know that Dynamoose has a dynamodb parser, I think its Schema.prototype.dynamodbparse(). However, that doesn't work as expected.

import { DYNAMODB_EVENT } from '../../constant';
import _get from 'lodash/get';
import { Entry } from '../../model/entry';
import { applyEntry } from './applyEntry';

async function entryStream(event) {
  await Promise.all(
    event.Records.map(async record => {
      // If this record is being deleted, do nothing
      if (DYNAMODB_EVENT.Remove === record.eventName) {
        return;
      }

      // What I've tried:
      let entry = new Entry(record.dynamodb.NewImage);

      // What I wish I could do
      entry = new Entry(Entry.schema.dynamodbparse(record.dynamodb.newImage));
      await applyEntry(entry);
    })
  );
}

export const handler = entryStream;

So is there a way to instantiate a Dynamoose model from DynamoDB's AttributeValue format? Has anyone else done this?

The alternative, is that I simply extract the key from the record, and then make a trip to the database using Model.get({ id: idFromEvent }); But I think that would be inefficient, since the record was just handed to me from the stream.


Solution

  • I solved it by using AWS.DynamoDB.Converter.unmarshall to parse the object before passing to Dynamoose.

    import { DYNAMODB_EVENT } from '../../constant';
    import _get from 'lodash/get';
    import { Entry } from '../../model/entry';
    import { applyEntry } from './applyEntry';
    
    // https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/Converter.html#unmarshall-property
    var AWS = require('aws-sdk');
    var parseDynamo = AWS.DynamoDB.Converter.unmarshall;
    
    async function entryStream(event) {
      await Promise.all(
        event.Records.map(async record => {
          // If this record is being deleted, do nothing
          if (DYNAMODB_EVENT.Remove === record.eventName) {
            return;
          }
    
          entry = new Entry(parseDynamo(record.dynamodb.newImage));
          await applyEntry(entry);
        })
      );
    }
    
    export const handler = entryStream;