关系型数据库设计转换为mongoDB/mongoose设计

7

我最近开始在我的新的Node.js应用程序中使用mongoDB和mongoose。以前只使用过关系型数据库,现在我正在努力适应mongoDB/noSQL的思维方式,如去规范化和缺乏外键关系。我有这个关系型数据库设计:

**Users Table**

user_id
username
email
password

**Games Table**

game_id
game_name

**Lobbies Table**

lobby_id
game_id
lobby_name

**Scores Table**

user_id
game_id
score

每个大厅属于一款游戏,多个大厅可以属于同一款游戏。用户还有不同的游戏得分。对于我的用户架构,到目前为止我有以下内容:

var UserSchema = new mongoose.Schema({
    username: {
        type: String,
        index: true,
        required: true,
        unique: true
    },
    email: {
        type: String,
        required: true
    },
    password: {
        type: String,
        required: true
    }
});

我的问题是,我应该如何将关系型设计转换为mongoDB/mongoose的模式?谢谢!


编辑 1

我已经尝试创建所有的模式,但我不知道这是否是正确的方法。

var UserSchema = new mongoose.Schema({
    _id: Number,
    username: {
        type: String,
        index: true,
        required: true,
        unique: true
    },
    email: {
        type: String,
        required: true
    },
    password: {
        type: String,
        required: true
    },
    scores: [{ type: Schema.Types.ObjectId, ref: 'Score' }]
});

var GameSchema = new mongoose.Schema({
    _id: Number,
    name: String
});

var LobbySchema = new mongoose.Schema({
    _id: Number,
    _game: { type: Number, ref: 'Game' },
    name: String
});

var ScoreSchema = new mongoose.Schema({
    _user : { type: Number, ref: 'User' },
    _game : { type: Number, ref: 'Game' },
    score: Number
});
4个回答

13

Mongoose被设计成这样一种方式,使得您可以相对轻松地以关系模式建立表格,并根据模式中定义的ref填充关系数据。需要注意的是,如果您填充过多或嵌套填充,将会遇到性能瓶颈。

您在Edit 1中的方法大体上是正确的,但通常不应该基于Number填充远程的ref或将模型的_id设置为Number,因为Mongo使用自己的哈希机制来管理_id,这通常是一个带有暗示_idObjectId。如下所示的示例:

var ScoreSchema = new mongoose.Schema({
    user : { type: Schema.Types.ObjectId, ref: 'User' },
    game : { type: Schema.Types.ObjectId, ref: 'Game' },
    score: Number
});
如果出于某种原因您需要为记录维护数字ID,请考虑将其命名为uid或其他不会与Mongo/Mongoose内部冲突的名称。祝好运!

参考名称必须是大写的第一个字母吗? - Erkam KUCET
1
@ErkamKUCET 这取决于您所引用的模型的命名方式。 - Dmitry Masley

5

首先,你提到了一些很好的观点。Mongoose 的优点在于你可以轻松地将模式与单个集合连接并绑定,并在其他集合中引用它们,从而获得关系型和非关系型数据库的最佳功能。

此外,你不需要将 _id 作为一个属性,Mongo 会为你自动添加它。

我使用mongoose.Schema.Types.ObjectId类型对你的模式进行了一些更改。

var UserSchema = new mongoose.Schema({
    username: {
        type: String,
        index: true,
        required: true,
        unique: true
    },
    email: {
        type: String,
        required: true
    },
    password: {
        type: String,
        required: true
    },
    scores: [{ type: Schema.Types.ObjectId, ref: 'Score' }]
});

var GameSchema = new mongoose.Schema({
    name: String
});

var LobbySchema = new mongoose.Schema({
    _game: { 
       type: mongoose.Schema.Types.ObjectId, 
       ref: 'Game' 
     },
    name: String
});

var ScoreSchema = new mongoose.Schema({
    _user : { 
         type: mongoose.Schema.Types.ObjectId, 
         ref: 'User' 
       },
    _game : { 
         type: mongoose.Schema.Types.ObjectId, 
         ref: 'Game' 
       },
    score: Number
});

这将允许您查询数据库并填充任何引用的集合和对象。

例如:

ScoreSchema.find({_id:##userIdHere##})
           .populate('_user')
           .populate('_game')  
           .exec(function(err, foundScore){
                   if(err){
                      res.send(err)
                    } else {
                 res.send(foundScore)
   }
}

这将填充相关的用户和游戏属性。

所以您分配给“ref”属性的“得分、用户和游戏”是您的集合的名称吗? - Woppi

4

您编辑了帖子,我认为这很好。至少不错 :)

请查看Mongoose Query Population。 它非常有用,可以获取相关数据。

var mongoose = require('mongoose'),
    ObjectId = mongoose.Schema.Types.ObjectId

// code, code, code

function something(req, res) {
  var id = req.params.id
  // test id
  return Lobby.findOne({_id: new ObjectId(id)})
    .populate('_game')
    .exec(function(error, lobby) {
       console.log(lobby._game.name);
     });
}

0

有两种方法(我知道的)。您可以存储一个id(已索引),然后在查询第一张表后,再查询第二张表以获取信息,因为没有联接。这意味着如果您从一张表中获取用户id,则需要对用户表进行多次查询以获取用户数据。

另一种方法是将其全部存储在一张表中,即使它是重复的。例如,如果您只需要存储用户的屏幕名称和其他内容,则将其与其他数据一起存储,即使它已经在用户表中。我相信其他人会知道更好/不同的方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接