多用户类型的MongoDB架构设计

9

我即将构建一个 Node.js+Express+Mongoose 应用程序,希望能够借助社区的智慧并获得有关最佳实践和创建高效架构设计的建议。

我的应用程序将包括 2 种不同类型的用户,即“教师”和“学生”。每个用户都将拥有一个用户资料,但是需要为每种帐户类型提供不同的字段。此外,“教师”和“学生”之间还会存在关系,其中“学生”最初将拥有1 名教师(未来可能还会有更多),而“教师”将拥有多名学生

我对如何处理这个问题的最初想法是创建一个通用的用户模型以及每个用户类型的资料模型(studentProfile 模型和 teacherProfile 模型),然后在用户模型中引用相应的资料模型,如下所示 (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的population功能。有没有理由反对这样做呢?

再次感谢!


1
我建议每个文档都是完整的。因此,我认为使用dbRef不是一个好主意(一个文档限制为16MB,除非您的文档将超过此限制,否则不要使用dbRef)。我认为教师和学生应该是两个集合而不是一个。请告诉我为什么您想使用一个集合? - Flying Fisher
@FlyingFisher,使用一个集合没有特别的原因,只是为了充分利用无模式数据库。使用引用是传统关系型数据库采用的方法,我只是想知道是否有一种更新、更现代的方法。那么选项A是否是最好的路线...减去dbRef...并只向学生和教师模式添加user_id?感谢您的意见。 - Deadlift
1
根据我的使用经验,MongoDB中文档的完整性比数据冗余更为重要。因此,我建议学生在教师信息中不仅包含_id,还应该包含更多数据。这样做有一个好处,当你获取一个文档时,你需要的一切都在其中。例如,当你展示学生信息时,无需获取教师集合;当你展示教师信息时,无需获取学生集合。 - Flying Fisher
这个问题使用判别器是一个好的解决方案吗? - Diaa Eddin
2个回答

0
你可以尝试使用.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

请查看文档。


0
一个可行的方法是以下内容:
//为登录目的创建用户模型,其中您的角色将定义导航到哪个门户
    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);

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