awslabs / dynamodb-data-mapper-js

A schema-based data mapper for Amazon DynamoDB.
https://awslabs.github.io/dynamodb-data-mapper-js/
Apache License 2.0
816 stars 106 forks source link

Cannot read property 'B' of undefined exception rised on batchPut #199

Closed shontauro-zz closed 3 years ago

shontauro-zz commented 3 years ago

My code: async batchAddEventSubscriptions(events: EventSubscription[]) { for (const e of events) { e.generatePK1; e.generateSK1 } for await (const persisted of this.dataMapper.mapper.batchPut(events)) { // items will be yielded as they are successfully written console.log('Saved Item \n', persisted); } }

Stack Trace:

TypeError: Cannot read property 'B' of undefined
    at itemIdentifier (/Users/shontauro/Documents/trinitip/web-socket-notification-service/node_modules/@aws/dynamodb-data-mapper/src/DataMapper.ts:1249:25)
    at DataMapper.<anonymous> (/Users/shontauro/Documents/trinitip/web-socket-notification-service/node_modules/@aws/dynamodb-data-mapper/src/DataMapper.ts:1087:26)
    at step (/Users/shontauro/Documents/trinitip/web-socket-notification-service/node_modules/@aws/dynamodb-data-mapper/node_modules/tslib/tslib.js:141:27)
    at Object.next (/Users/shontauro/Documents/trinitip/web-socket-notification-service/node_modules/@aws/dynamodb-data-mapper/node_modules/tslib/tslib.js:122:57)
    at resume (/Users/shontauro/Documents/trinitip/web-socket-notification-service/node_modules/@aws/dynamodb-data-mapper/node_modules/tslib/tslib.js:208:48)
    at fulfill (/Users/shontauro/Documents/trinitip/web-socket-notification-service/node_modules/@aws/dynamodb-data-mapper/node_modules/tslib/tslib.js:210:35)
FrankDMartinez commented 3 years ago

@shontauro I am having this same issue with batchGet(). What was your solution?

Mozart-Alkhateeb commented 3 years ago

@shontauro having same issue with batchDelete() using same example as the docs:

const toRemove = [
    Object.assign(new MyDomainObject, {id: 'foo', createdAt: new Date(946684800000)}),
    Object.assign(new MyDomainObject, {id: 'bar', createdAt: new Date(946684800001)})
];
for await (const found of mapper.batchDelete(toRemove)) {
    // items will be yielded as they are successfully removed
}

"@aws/dynamodb-data-mapper": "^0.7.3"

shontauro-zz commented 3 years ago

I did this (TypeScript):

async removeEventSubscriptionsByConnectionId(ev: EventSubscription) { const keyCondition = { ConnectionId: ev.ConnectionId, }; const queryOptions = { limit: 25, // DynamoDB MAX Hard Limit indexName: FIND_CONNECTIONS_BY_ID_INDEX_NAME, }; const paginator = this.dataMapper.mapper .query(EventSubscription, keyCondition, queryOptions) .pages();

for await (const page of paginator) {
  console.log(
    `REMOVE PAGE -- Count: ${paginator.count} - scannedCount: ${paginator.scannedCount} - lastEvaluatedKey: ${paginator.lastEvaluatedKey} \n`,
  );
  for await (const deletedItem of this.dataMapper.mapper.batchDelete(
    page,
  )) {
    // items will be yielded as they are successfully removed
    console.log('Deleted Item \n', deletedItem);
  }
}

}

Mozart-Alkhateeb commented 3 years ago

My problem was different, I added the sort key to the objects I was trying to delete and it worked. and btw I think using query you do not need to handle pagination manually, it will do this internally.

      let toRemove = [];

      const res = dataMapper.query(Chat,
        { userId: userId },
        { indexName: 'myIndexName', projection: ['id', 'userId'] }
      )

      for await (const item of res ) {
        toRemove.push(Object.assign(new Chat, { id: item.id, userId: item.userId }))
      }

I have more than 500 items and are returned with no errors next step is to delete them

      for await (const found of dataMapper.batchDelete(toRemove)) {
        // items will be yielded as they are successfully removed
        //console.log('found', found)
      }
edenriquez commented 3 years ago

For anyone struggling with batchGet I'm getting the same error passing projection in batchGet from the mapper. this is the work around I found:

Note: Can confirm that scan works as expected but scan does not allow pass multiple ids as batch operations.

So the work around I found was to use @aws/dynamodb-batch-iterator , this is my code in case someone wants to query and filter fields in a dynamo response

import { BatchGet } from "@aws/dynamodb-batch-iterator";
const client = new DynamoDB({ region: "us-east-1" });
const keysToGet = [];
keys.map((key) => {
      keysToGet.push([
        "your_table_name",
        { your_primary_key: { S: key.primary_key } },
      ]);
    });

 for await (const response of new BatchGet(client, keysToGet, {
      PerTableOptions: {
        your_table_name: {
          ProjectionExpression: "field, or_fields",
        },
      },
    })) {
      console.log(response);
    }

the same but using mapper does not work, it gives me the error mentioned here

keys.map((key) => {
      keysToGet.push(
        Object.assign(new YourDynamoDbModel(), {
          your_primary_key: key.primary_key,
        })
      );
    });
for await (const response of mapper.batchGet(keysToGet, {
      perTableOptions: {
        your_table_name_without_prefix: {
          projection: ["field"],
        },
      },
    })) {
     console.log(response)
    }
wakeupmh commented 2 years ago

I had the following code, how can i make this work? This error is annoying :(

 for await (const employee of this.mapper.batchGet(employeesToGet)) {
      employees.push(employee)
    }

    return employees

and I had the following error: Cannot read property 'B' of undefined exception

Why developers make an api to batch get knowing this will not work?

wakeupmh commented 2 years ago

@shontauro I am having this same issue with batchGet(). What was your solution?

Hey dude, did u find a solution?

edenriquez commented 2 years ago

@wakeupmh use

import { BatchGet } from "@aws/dynamodb-batch-iterator";
const client = new DynamoDB({ region: "us-east-1" });
keysToGet.push([
  "your_table_name",
  { your_primary_key: { S: key.primary_key } },
]);

...
for await (const response of new BatchGet(client, keysToGet, {
...

instead

for await (const response of this.mapper.batchGet(employeesToGet)) {
shreyasood20 commented 2 years ago

Cannot read property 'B' of undefined exception

I was getting this error for both my BATCHGET and BATCHPUT method. i resolved it for batchget ;-> the issue was i had to pass primary key(both partition key and range key). But was trying to get it through only partition key. hence the issue. i used aws dynamodb mapper

cplummer-linq commented 2 years ago

For anyone getting this issue, and you need more details... I highly recommend temporarily patching DataMapper.js in your node_modules folder, and adding more details to the error message.

image