Dynamoose 使用

Dynamoose 是一个DynamoDB的建模工具.

安装

1
npm install dynamoose

使用

配置

  1. 环境变量

    1
    2
    3
    4
    # Set environment variables
    export AWS_ACCESS_KEY_ID="Your AWS Access Key ID"
    export AWS_SECRET_ACCESS_KEY="Your AWS Secret Access Key"
    export AWS_REGION="us-east-1"
  2. 配置AWS Object

    1
    2
    3
    4
    5
    dynamoose.AWS.config.update({
    accessKeyId: 'AKID',
    secretAccessKey: 'SECRET',
    region: 'us-east-1'
    });
  3. AWS IAM role配置
    https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html

  4. 本地

    1
    2
    dynamoose.local(); // This will set the server to "http://localhost:8000" (default)
    dynamoose.local("http://localhost:1234") // This will set the server to "http://localhost:1234"

建模及使用

建模

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
{
name: 'DMovie',
schema: {
fields: {
year: {
type: Number,
validate: function (v) {
return v > 0;
},
hashKey: true
},
title: {
type: String,
rangeKey: true,
index: true,
name: "title-index",
ProjectionType: "ALL"
},
info: {
type: Object,
},
flag: {
type: Number,
index: true,
name: "flag-index",
// ProjectionType: ALL
},
},
config: {
throughput: { // Sets the throughput of the DynamoDB table on creation
read: 5,
write: 2
},
useNativeBooleans: true, // Store Boolean values as Boolean (‘BOOL’) in DynamoDB
useDocumentTypes: true, //Store Objects and Arrays as Maps (‘M’) and Lists (‘L’) types in DynamoDB.
saveUnknown: true, // Specifies that attributes not defined in the schema will be saved and retrieved. This defaults to false.
timestamps: { // Defines that schema must contain fields to control creation and last update timestamps. If it is set to true, this fields will be createdAt for creation date and updatedAt for last update
createdAt: 'creationDate',
updatedAt: 'lastUpdateDate'
}
}
}
}

setting

1
2
3
4
5
6
7
8
{
create: true, // Create table in DB, if it does not exist,
update: false, // Update remote indexes if they do not match local index structure
waitForActive: true, // Wait for table to be created before trying to use it
waitForActiveTimeout: 180000, // wait 3 minutes for table to activate
prefix: '', // Default prefix for all DynamoDB tables
suffix: '' // Default suffix for all DynamoDB tables
}

1
var DMovie =  builder(config);

添加记录

1
2
3
4
5
6
7
8
9
10
11
return DMovie.create({
"year": 2018,
"title": "Rush 1",

"info": "Info 1"
}).then(data => {
expect(data.year).to.be.equal(2018);
expect(data.title).to.be.equal('Rush 1');
expect(data).to.be.have.property('creationDate');
expect(data).to.be.have.property('lastUpdateDate');
});

查询

1
2
3
4
5
6
7
8
9
10
11
12
13
it('DMovie record should be query successfully', () => {
return DMovie.get({
"year": 2018,
"title": "Rush 1"
}).then(data => {
console.log('data ', data)
expect(data.year).to.be.equal(2018);
expect(data.title).to.be.equal('Rush 1');
expect(data.info).to.be.equal('Info 1');
expect(data).to.be.have.property('creationDate');
expect(data).to.be.have.property('lastUpdateDate');
});
});

更新记录

1
2
3
4
5
6
7
8
9
10
11
12
return DMovie.update({
"year": 2018,
"title": "Rush 1",
},
{"test": "I am updated", "info": "Info 2"})
.then(data => {
expect(data.year).to.be.equal(2018);
expect(data.title).to.be.equal('Rush 1');
expect(data.info).to.be.equal('Info 2');
expect(data).to.be.have.property('creationDate');
expect(data).to.be.have.property('lastUpdateDate');
});

删除记录

1
2
3
4
5
6
7
8
it('DMovie record should be deleted successfully', () => {
return DMovie.delete({
"year": 2018,
"title": "Rush 1"
}).then((data) => {
expect(data.year).to.be.equal(2018);
});
});

批量添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
it('DMovie record should be batch added successfully', () => {
var allMovies = JSON.parse(fs.readFileSync(normalPath + '/movie2.json', 'utf8'));
expect(allMovies.length).to.be.equal(655);

var times = 10, flag = 0, items = [];
var iter = function (model) {
flag++;
var v = flag % 3;
items.push(new DMovie({
"year": 2013,
"title": "v." + flag + ' ' + model.title,
"info": model.info,
"flag": v
}));
};

for (var i = 0; i < times; i++) {
allMovies.forEach(iter);
}

return DMovie.batchPut(items).then(data => {
expect(Object.keys(data.Responses)).to.have.lengthOf(0);
expect(Object.keys(data.UnprocessedItems)).to.have.lengthOf(0);
});
});

DynamoDB 低级 API 支持批量读取和写入操作.
批量操作可以容忍批处理中的个别请求失败。举例来说,假设一个 BatchGetItem 请求读取五个项目。即使某些底层 GetItem 请求失败,这也不会导致整个 BatchGetItem 操作失败。另一方面,如果所有五个读取操作都失败,则整个 BatchGetItem 将失败。
批量操作会返回有关各失败请求的信息,以便您诊断问题并重试操作。对于 BatchGetItem,在请求的 UnprocessedKeys 参数中会返回有问题的表和主键。对于 BatchWriteItem,在 UnprocessedItems 中返回类似信息。
如果 DynamoDB 返回了任何未处理的项目,应对这些项目重试批量操作。然而,我们强烈建议您使用指数回退算法。如果立即重试批量操作,底层读取或写入请求仍然会由于各表的限制而失败。如果使用指数回退延迟批量操作,批处理中的各请求成功的可能性更大。

查询索引

1
2
3
4
5
6
7
8
9
10
it('DMovie record with index#title-index should be counted successfully', () => {
// same as: DMovie.query('flag').using('FlagTitleIndex').eq(0).exec().then(result => {
return DMovie.query('flag').using('FlagTitleIndex').eq(0).exec().then(result => {
console.log('result', result)
// result.splice(0,result.length)
expect(result.count).to.be.equal(1824);
expect(result.scannedCount).to.be.equal(1824);
expect(Object.keys(result.lastKey)).to.have.lengthOf(3);
});
});

删除表

1
2
3
4
5
6
7
8
9
it('deleteTable should be called successfully', () => {
console.log('DMovie.tableName ', DMovie.modelName)
return deleteTable({
TableName: DMovie.modelName
}).then((result) => {
expect(result.TableDescription).to.have.property('CreationDateTime');
expect(result.TableDescription).to.have.property('TableArn');
});
});