如何在 Dynamoose/DynamoDB 中建模关系?

Lui*_*tin 3 amazon-dynamodb dynamoose

我需要将用户与发票链接起来。在 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);
Run Code Online (Sandbox Code Playgroud)

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

Cha*_*ish 5

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

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

我之所以说它不是“真正的”关系数据库,是因为您仍然可以以关系类型的方式对数据进行建模。使用 DynamoDB 高效地完成此操作并非不可能。

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


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

这看起来像下面这样。

const userSchema = new dynamoose.Schema({
    "id": String,
    // ...
});
const User = dynamoose.model("User", userSchema);

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

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
Run Code Online (Sandbox Code Playgroud)

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


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

简而言之,您可以通过使用查询来在单个请求中获取您要查找的数据的方式对数据进行建模。使用哈希键和范围键将数据划分为有效的模式。

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

Dynamoose 中的示例如下:

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

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


希望这有助于回答您的问题。Dynamoose 有一个 Slack 房间,您也可以加入,以解答有关您的用例的更多具体问题(您可以在 GitHub 存储库README中找到加入链接)。如果有任何不明白的地方或者您需要更清晰的信息,请随意对此答案发表评论。