Skip to content

Expressions: Projection builder

Eugene Lazutkin edited this page Apr 23, 2026 · 1 revision

Expressions: Projection builder

See also (AWS JS SDK v3): Projection expressions · Expression attribute names. Vocabulary: Concepts.

Projection is the primary read-performance lever for DynamoDB. Items can carry dozens of attributes, some of them large — embedded blobs, serialized graphs, long text. A read that only needs two or three of them shouldn't pay the cost of transferring the full item. Projection tells DynamoDB which attributes to return; everything else stays on the server. Result: less read capacity consumed (especially on Scan / Query pages), less scan-byte pressure, less network egress back to your client.

Pair with patches on the write side for the symmetric win — read a slice, modify only what changed, write the delta. The fields you don't touch never leave the server either way.

addProjection(params, fields, projectionFieldMap?, skipSelect?, separator?) builds DynamoDB's ProjectionExpression from a list of fields, with attribute-name aliasing and de-duplication. It's an additive builder — mutates params in place and returns it.

import {addProjection} from 'dynamodb-toolkit/expressions';

const params = addProjection(
  {/* existing params */},
  ['name', 'climate', 'terrain']
);
// ProjectionExpression: "#pj0,#pj1,#pj2"
// EAN: {#pj0: 'name', #pj1: 'climate', #pj2: 'terrain'}
// Select: 'SPECIFIC_ATTRIBUTES'

Signature

function addProjection<T extends object>(
  params: T,
  fields?: string | string[] | Record<string, unknown> | null,
  projectionFieldMap?: Record<string, string>,
  skipSelect?: boolean,
  separator?: string
): T;

fields accepts:

  • 'name,climate,terrain' (comma string)
  • ['name', 'climate', 'terrain']
  • {name: 1, climate: 1} (object — keys become fields)
  • null / undefined / '' — no-op, returns params unchanged

Pass skipSelect: true when you don't want Select: 'SPECIFIC_ATTRIBUTES' set (e.g., Select: 'COUNT' paths).

Field-name aliasing

projectionFieldMap rewrites the first segment of each path:

addProjection({}, ['desc'], {desc: 'description'});
// EAN: {#pj0: 'description'}; ProjectionExpression: "#pj0"

Use this when the wire-side name differs from the storage column name. The Adapter forwards its projectionFieldMap constructor option here.

De-duplication

If you call addProjection multiple times against the same params, duplicates are detected and the projection is collapsed:

let p = addProjection({}, ['name', 'climate']);
p = addProjection(p, ['climate', 'terrain']);
// ProjectionExpression: "#pj0,#pj1,#pj2" — climate not repeated

Dotted paths

Same convention as the other builders — pure-digit segments become array indices:

addProjection({}, ['config.thresholds.0', 'tags.2']);
// ProjectionExpression: "#pj0.#pj1[0],#pj2[2]"

When to use it standalone

The Adapter applies projection automatically in getByKey / getByKeys / getList / getListByParams when fields is supplied. Use addProjection directly when you're building params for applyTransaction / getBatch / a custom Query/Scan pipeline outside the Adapter.

Clone this wiki locally