多用户类型的 MongoDB 模式设计

Posted

技术标签:

【中文标题】多用户类型的 MongoDB 模式设计【英文标题】:MongoDB schema design for multiple user types 【发布时间】:2016-09-21 02:36:09 【问题描述】:

我即将构建一个 Node.js+Express+Mongoose 应用程序,我想挑选社区的大脑并获得一些关于最佳实践和创建高效架构设计的建议.

我的应用程序将包含 2 种不同的用户类型,即“教师”和“学生”。每个都将有一个用户个人资料,但需要每种帐户类型使用不同的字段。 “老师”和“学生”之间也会有关系,其中“学生”最初会有 1 位老师(未来可能会有更多),而“老师”将有 >许多学生

我最初的想法是为每个用户类型(studentProfile 模型和 teacherProfile em> 模型),然后在 User 模型中引用适当的配置文件模型,如下所示 (A):

var UserSchema = new Schema(
    name: String,
    email: String,
    password: String,
    role: String, /* Student or Teacher */
    profile:  type: ObjectID, refPath: 'role' 
);

var studentProfileSchema = new Schema(
    age: Number,
    grade: Number,
    teachers: [ type: ObjectID, ref: 'Teacher' ] 
);

var teacherProfileSchema = new Schema(
    school: String,
    subject: String 
);

或者我是否直接在 User 模型中嵌入两个配置文件的所有字段,然后填充特定用户类型所需的字段,如下所示 (B):

var UserSchema = new Schema(
    name: String,
    email: String,
    password: String,
    role: String, /* Student or Teacher */
    profile: 
       age: Number,
       grade: Number,
       school: String,
       subject: String
    ,
    relationships: [ type: ObjectID, ref: 'User' ]
);

选项 B 的缺点是我不能真正使用 Mongoose 的 required 字段属性。但是我不应该首先依赖 Mongoose 进行验证,而是让我的应用程序逻辑进行验证吗?

除此之外,还将有一个单独的集合/模型用于记录学生的活动和任务,并为每个记录的任务引用学生的 ID,即:

var activitySchema = new Schema(
    activity: String,
    date: Date,
    complete: Boolean,
    student_id: ObjectID
);

我的数据库设计是否正确?任何反馈都将不胜感激,因为我重视来自这个社区的任何意见,并且一直在寻求学习和提高我的技能。有什么比来自该领域志同道合的个人和专家更好的方法:)

此外,您可以看到我正在利用 Mongoose 的人口功能。有什么理由不建议这样做吗?

再次感谢!

【问题讨论】:

我建议每个文件都是完整的。所以我认为使用 dbRef 不是一个好主意(一个文档限制为 16MB,除非你的文档会超过这个限制,否则不要使用 dbRef)。我认为老师和学生应该是两个集合而不是一个集合。请告诉我你为什么要使用一个集合? @FlyingFisher 除了尝试充分利用无模式数据库之外,没有特别的理由使用一个集合。使用引用是 RDBMS 采用的一种更传统的方法,我只是想知道是否有更新、更现代的方法。那么选项A会是最好的路线......减去dbRef......并且只需将user_id添加到学生和教师模式?感谢您的意见。 对于我使用MongoDB的经验来说,文档的完整性比数据冗余更重要。所以我建议学生包含更多关于老师的数据,而不仅仅是_id。出于一个目的,当您获得一份文件时,您需要的一切都在其中。例如显示学生信息时,无需获取教师集合,显示教师信息时,无需获取学生集合。 判别器是解决这个问题的好方法吗? 【参考方案1】:

您可以尝试使用.discriminator(...) 函数来构建用户模式,以便其他模式可以直接“继承”属性。

const options = discriminatorKey: 'kind';

const UserSchema = new Schema(
    name: String,
    email: String,
    password: String,
    /* role: String, Student or Teacher <-- NO NEED FOR THIS. */
    profile:  type: ObjectID, refPath: 'role' 
, options);

const Student = User.discriminator('Student', new Schema(
    age: Number,
    grade: Number,
    teachers: [ type: ObjectID, ref: 'Teacher' ]
, options));

const Teacher = User.discriminator('Teacher', new Schema(
    school: String,
    subject: String
, options));

const student = new Student(
    name: "John Appleseed",
    email: "john@gmail.com",
    password: "123",
    age: 18,
    grade: 12,
    teachers: [...]
);

console.log(student.kind) // Student

查看文档。

【讨论】:

【参考方案2】:

一种方法可能如下:

//创建用于登录目的的用户模型,您的角色将在其中定义要导航到的门户

    const userSchema = new mongoose.Schema(
  _id:mongoose.Schema.Types.ObjectId,
  name: type:String,required:true,
  password: type: String, required: true,
  email: type: String, required: true,
role:type:String,required:true
,timestamps:true);

export default mongoose.model("User", userSchema);

//一个学生模式,包含关于学生的信息,还带有来自教师模型的教师 ID

const studentSchema = new mongoose.Schema(
  _id:mongoose.Schema.Types.ObjectId,
  age:type:Number,
  grade:type:String,
teacher:type:mongoose.Schema.Types.ObjectId,ref:'Teachers'
,timestamps:true);

export default mongoose.model("Students", studentSchema);

//可以记录老师的老师模型

const teacherSchema = new mongoose.Schema(
  _id:mongoose.Schema.Types.ObjectId,
  subject:type:String,
  School:type:String,
,timestamps:true);

export default mongoose.model("Teachers", teacherSchema);

【讨论】:

以上是关于多用户类型的 MongoDB 模式设计的主要内容,如果未能解决你的问题,请参考以下文章

mongodb模式模型设计及编码-Mongoose

多用户账户的 MongoDB/Mongoose 模式

如何在 Servlet 中使用 DAO 设计模式方法将用户输入存储到 MongoDB?

MongoDB Mongoose 模式设计

多商品订单的 MongoDB 模型设计

MongoDB Schema 设计建议