2

我需要用户与发票相关联。在 SQL 数据库中,它将是一个外键。我怎样才能在 Dynamoose 中做到这一点?

const dynamoose = require('dynamoose');
const uuid = require('uuid');
const config = require('../config/config').get(process.env.NODE_ENV);

dynamoose.aws.sdk.config.update({
    region: config.awsRegion,
    accessKeyId: config.awsAccessKeyId,
    secretAccessKey: config.awsSecretKey
});

const userSchema = new dynamoose.Schema({
    uid: {
        type: String,
        hashKey: true,
        default: uuid.v1(),
    },
    name: {
        type: String,
        required: true
    },
    email: {
        type: String,
        required: true
    },
    password: {
        type: String,
        require: true
    },
    token: {
        type: String
    }
});

module.exports = dynamoose.model('User', userSchema);

其他表中的每条记录都必须拥有所有者作为创建它的用户。

4

1 回答 1

3

与 SQL 相比,这是一个非常复杂的话题。

DynamoDB 并不是真正的关系数据库。在 SQL 中,您将向数据库发送一个命令,它会对其进行处理,并返回结果、引用和所有内容。DynamoDB 没有内置关系功能。我的意思是您可以向用户发出获取请求,并在用户内部存储发票的密钥或 ID,然后以这种方式链接它们然后获取发票。但此时您正在向服务器发送 2 个往返请求。这显然在规模上效率不高。

我之所以说它不是“真正的”关系数据库,是因为您仍然可以以关系类型的方式对数据进行建模。使用 DynamoDB 有效地做到这一点并非不可能。

下面我将解释两种方法,首先是存储 ID 的效率较低的方法,然后向数据库发出 2 个请求。其次是 DynamoDB 推荐的更复杂的方法,这种方法非常有效。


Dynamoose 有一个概念,您可以通过传入一个模型作为属性的类型来建立这种关系。它将为您存储密钥,您可以致电document.populate获取发票。该document.populate调用将向数据库发出第二个请求,并且效率不高。

这看起来像下面这样。

const gameSchema = new dynamoose.Schema({
    "id": String,
    "state": String,
    "user": User
});

const game = await Game.get("GAMEID1");
console.log(game.user); // This will print the user key, not the actual user document
const populatedGame = await game.populate();
console.log(populatedGame.user); // This will print the actual user document

请记住,这不是有效的。我真的不推荐这种方法,但要使用它并让它快速工作(不像高性能那样快,但在快速迁移现有代码方面很快),它可以完成工作。


更推荐的解决方案是彻底重新考虑您的数据结构。这与单表设计有关。我强烈建议您观看 AWS reInvent 2019上的“使用 Amazon DynamoDB 进行数据建模演讲”,以了解有关这方面最佳实践的更多信息。

简短的版本是您以一种可以使用查询在单个请求中获取您正在查找的数据的方式对数据进行建模。使用哈希和范围键将数据划分为有效的模式。

您基本上会有一个用户模式和一个发票模式,但两者都有一个模型(表)。这在 Dynamoose 中看起来有点奇怪(希望将来我们可以更改 API 以使其更清洁)。但这很奇怪,因为 Dynamoose 中的模型代表一个表,而不是一个实体。我希望在 v3 中我们能够重新思考它是如何工作的。

这在 Dynamoose 中的外观示例如下:

const Cat = dynamoose.model("Cat", [
    new dynamoose.Schema({"id": String, "name": String}),
    {"id": String, "age": Number}
]);

然后你可以使用查询来获取你想要的数据。这确实需要巨大的思维转变,但这就是您如何看待 DynamoDB 经常谈论的那些惊人的大规模性能提升。


希望这有助于回答您的问题。Dynamoose 有一个 Slack 会议室,您也可以加入以解决针对您的用例的更多具体问题(您可以在 GitHub 存储库README中找到加入的链接)。如果有什么没有意义或您需要更清楚,请随时评论此答案。

于 2020-11-23T19:04:37.977 回答