DEV Community

Cover image for How to Get Item by ID From Dynamodb Table with TypeScript?
Radzion Chachura
Radzion Chachura

Posted on • Originally published at radzion.com

How to Get Item by ID From Dynamodb Table with TypeScript?

Watch on YouTube

My app has a table with users, and I usually query just a handful of fields instead of the whole user object. That's why we have a second parameter called attributes. It is an array of user keys.

export async function getUserById<T extends (keyof User)[]>(
  id: string,
  attributes?: T
): Promise<Pick<User, T[number]> | undefined> {
  const { Item } = await documentClient
    .get(mergeParams(getUserItemParams(id), projectionExpression(attributes)))
    .promise()

  return Item as Pick<User, T[number]>
}
Enter fullscreen mode Exit fullscreen mode

To simplify interactions with DynamoDB, I have a handful of helpers.

projectionExpression converts an array to an object we can pass to the document client.

export const projectionExpression = (attributes?: string[]) => {
  if (!attributes) {
    return {}
  }

  const ProjectionExpression = attributes
    .map((attr) => `${attr.includes(".") ? "" : "#"}${attr}, `)
    .reduce((acc, str) => acc + str)
    .slice(0, -2)

  const attributesToExpression = attributes.filter(
    (attr) => !attr.includes(".")
  )

  const ExpressionAttributeNames = attributesToExpression.reduce<{
    [key: string]: string
  }>((acc, attr) => {
    acc["#" + attr] = attr
    return acc
  }, {})

  return attributesToExpression.length
    ? { ProjectionExpression, ExpressionAttributeNames }
    : { ProjectionExpression }
}
Enter fullscreen mode Exit fullscreen mode

I have a function like getUserItemParams for every table. It returns an object we need to get, update or delete an item.

export const getUserItemParams = (id: string) => ({
  TableName: tableName.users,
  Key: { id },
})
Enter fullscreen mode Exit fullscreen mode

Sometimes those helpers can return an object with a shared field ExpressionAttributeNames. To resolve such clashes, I use the mergeParams function.

export const mergeParams = (...params: any[]) =>
  params.reduce(
    (acc, param) =>
      Object.entries(param).reduce((acc, [key, value]) => {
        acc[key] = Array.isArray(value)
          ? [...acc[key], ...value]
          : typeof value === "object"
          ? { ...acc[key], ...value }
          : value
        return acc
      }, acc),
    {}
  )
Enter fullscreen mode Exit fullscreen mode

Top comments (0)

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up