我是mongodb
的新手,并且正在玩自我项目,用户可以订阅3-4种预定义的不同课程。每门课程每天1小时,学生可以订阅15天,30天或更长时间。
应用程序将存储学生的信息,他们订阅的课程(天数和天数)。
这是我的Mongoose Schema。
var mongoose = require('mongoose');
var schemaOptions = {
timestamps: true,
toJSON: {
virtuals: true
}
};
var courseSchema = new mongoose.Schema({
name: String
});
var studentSchema = new mongoose.Schema({
name: String,
email: { type: String, unique: true},
phone: String,
gender: String,
age: String,
city: String,
street: String,
picture: String,
course: [courseSchema],
subscriptionDays: Number,
daysPresent: [Date]
}, schemaOptions);
module.exports = mongoose.model('Student', studentSchema);
在这里,course
是3-4门课程中的任何一门,一名学生可以同时订阅一门或多门课程。 subscriptionDays
是他们订阅的天数,daysPresent
是他们参加课程的日期。
我不确定这是否是我项目的正确架构,到目前为止我能够做到这一点。
与架构的混淆是:
当订阅两门不同课程的学生到达时
学院,但只上一节课(课程),然后我不这么认为
schema支持这种情况,为此我想像这样修改courseSchema
,
var courseSchema = new mongoose.Schema({
name: String,
subsriptionDays: Number,
daysPresent: [Date]
});
但是,在这样做之后,我仍然很难对数据进行更改,例如每次学生参加课程时都必须将Date
插入到文档中。
Date
天内的数据。我可以从Mongo专家那里得到一些指导和建议吗? TIA
答案 0 :(得分:1)
我认为你基本上是在正确的轨道上,你对扩展设计的第二个想法。我真的只会扩展它,还包括一个"参考"进入"课程"本身而不仅仅是模式中嵌入的信息。
当您的使用案例出现问题时,可能最好用一个有效的例子来解决它们:
const async = require('async'),
mongoose = require('mongoose'),
Schema = mongoose.Schema,
ObjectId = Schema.Types.ObjectId;
mongoose.set('debug',true);
mongoose.connect('mongodb://localhost/school');
// Course model
const courseSchema = new Schema({
name: String,
info: String
});
const Course = mongoose.model('Course', courseSchema);
// Student Model
const studentCourseSchema = new Schema({
_id: { type: ObjectId, ref: 'Course' },
name: String,
subscriptionDays: Number,
daysPresent: [Date]
});
const studentSchema = new Schema({
name: String,
email: String,
courses: [studentCourseSchema]
});
studentSchema.index({ "email": 1 },{ "unique": true, "background": false });
const Student = mongoose.model('Student', studentSchema);
function logOutput(content) {
console.log( JSON.stringify( content, undefined, 2 ) )
}
async.series(
[
// Clear collections
(callback) =>
async.each(mongoose.models,
(model,callback) => model.remove({},callback),callback),
// Set up data
(callback) =>
async.parallel(
[
(callback) => Course.insertMany(
[
{ "name": "Course 1", "info": "blah blah blah" },
{ "name": "Course 2", "info": "fubble rumble" }
],
callback),
(callback) => Student.insertMany(
[
{ "name": "Bill", "email": "bill@example.com" },
{ "name": "Ted", "email": "ted@example.com" }
],
callback)
],
callback
),
// Give bill both courses
(callback) => {
async.waterfall(
[
(callback) => Course.find().lean().exec(callback),
(courses,callback) => {
courses = courses.map(
course => Object.assign(course,{ subscriptionDays: 5 }));
let ids = courses.map( c => c._id );
Student.findOneAndUpdate(
{ "email": "bill@example.com", "courses._id": { "$nin": ids } },
{ "$push": {
"courses": {
"$each": courses
}
}},
{ "new": true },
(err, student) => {
logOutput(student);
callback(err);
}
)
}
],
callback
)
},
// Attend one of bill's courses
(callback) => Student.findOneAndUpdate(
{ "email": "bill@example.com", "courses.name": 'Course 2' },
{ "$push": { "courses.$.daysPresent": new Date() } },
{ "new": true },
(err, student) => {
logOutput(student);
callback(err);
}
),
// Get Students .populate()
(callback) => Student.find().populate('courses._id')
.exec((err,students) => {
logOutput(students);
callback(err);
}
)
],
(err) => {
if (err) throw err;
mongoose.disconnect();
}
)
这样就可以给你一个关于你所询问的操作实际工作方式的样本。
向学生添加课程显示添加了几个课程,我认为您最好使用MongoDB的$push
功能。为了确保您没有添加已经存在的"查询"表达式实际上排除了选择,如果它们已经存在于courses数组中。在示例a" list"已通过,因此我们使用$nin
但只使用一个项目您只需使用$ne
:
{ "email": "bill@example.com", "courses._id": { "$nin": ids } },
{ "$push": { "courses": { "$each": courses } } },
添加有人参加的日期这实际上演示了您希望"位置匹配" "课程"中的项目为了知道要更新哪一个。这是通过提供类似于条件之前的匹配来实现的。而不是"排除"特定的数组元素。然后在实际的"更新"部分,我们应用相同的$push
运算符,以便我们可以附加到"daysPresent"
数组,但也使用位置$
运算符指向与匹配条件对应的正确数组索引位置:
{ "email": "bill@example.com", "courses.name": 'Course 2' },
{ "$push": { "courses.$.daysPresent": new Date() } },
作为奖励,还有一些操作显示了在他们自己的集合中保留"Courses"
列表与您可能不希望嵌入每个学生的其他信息之间的关系性质。
示例中的最后一个操作实际上执行.populate()
以实际从其他集合中提取此信息以供显示。
整个示例已使用mongoose.set('debug',true);
打开调试,因此您可以看到对MongoDB的实际调用对每个操作实际执行的操作。
还要熟悉此处使用的.findOneAndUpdate()
方法,以及MongoDB核心文档中的各种"update operators"。
Mongoose: courses.remove({}, {})
Mongoose: students.remove({}, {})
Mongoose: students.ensureIndex({ email: 1 }, { unique: true, background: false })
(node:10544) DeprecationWarning: Mongoose: mpromise (mongoose's default promise library) is deprecated, plug in your own promise library instead: http://mongoosejs.com/docs/promises.html
Mongoose: courses.insertMany([ { __v: 0, name: 'Course 1', info: 'blah blah blah', _id: 5944d5bc32c6ae2930174289 }, { __v: 0, name: 'Course 2', info: 'fubble rumble', _id: 5944d5bc32c6ae293017428a } ], null)
Mongoose: students.insertMany([ { __v: 0, name: 'Bill', email: 'bill@example.com', _id: 5944d5bc32c6ae293017428b, courses: [] }, { __v: 0, name: 'Ted', email: 'ted@example.com', _id: 5944d5bc32c6ae293017428c, courses: [] } ], null)
Mongoose: courses.find({}, { fields: {} })
Mongoose: students.findAndModify({ 'courses._id': { '$nin': [ ObjectId("5944d5bc32c6ae2930174289"), ObjectId("5944d5bc32c6ae293017428a") ] }, email: 'bill@example.com' }, [], { '$push': { courses: { '$each': [ { daysPresent: [], _id: ObjectId("5944d5bc32c6ae2930174289"), name: 'Course 1', subscriptionDays: 5 }, { daysPresent: [], _id: ObjectId("5944d5bc32c6ae293017428a"), name: 'Course 2', subscriptionDays: 5 } ] } } }, { new: true, upsert: false, remove: false, fields: {} })
{
"_id": "5944d5bc32c6ae293017428b",
"__v": 0,
"name": "Bill",
"email": "bill@example.com",
"courses": [
{
"subscriptionDays": 5,
"name": "Course 1",
"_id": "5944d5bc32c6ae2930174289",
"daysPresent": []
},
{
"subscriptionDays": 5,
"name": "Course 2",
"_id": "5944d5bc32c6ae293017428a",
"daysPresent": []
}
]
}
Mongoose: students.findAndModify({ 'courses.name': 'Course 2', email: 'bill@example.com' }, [], { '$push': { 'courses.$.daysPresent': new Date("Sat, 17 Jun 2017 07:09:48 GMT") } }, { new: true, upsert: false, remove: false, fields: {} })
{
"_id": "5944d5bc32c6ae293017428b",
"__v": 0,
"name": "Bill",
"email": "bill@example.com",
"courses": [
{
"subscriptionDays": 5,
"name": "Course 1",
"_id": "5944d5bc32c6ae2930174289",
"daysPresent": []
},
{
"subscriptionDays": 5,
"name": "Course 2",
"_id": "5944d5bc32c6ae293017428a",
"daysPresent": [
"2017-06-17T07:09:48.662Z"
]
}
]
}
Mongoose: students.find({}, { fields: {} })
Mongoose: courses.find({ _id: { '$in': [ ObjectId("5944d5bc32c6ae2930174289"), ObjectId("5944d5bc32c6ae293017428a") ] } }, { fields: {} })
[
{
"_id": "5944d5bc32c6ae293017428b",
"__v": 0,
"name": "Bill",
"email": "bill@example.com",
"courses": [
{
"subscriptionDays": 5,
"name": "Course 1",
"_id": {
"_id": "5944d5bc32c6ae2930174289",
"__v": 0,
"name": "Course 1",
"info": "blah blah blah"
},
"daysPresent": []
},
{
"subscriptionDays": 5,
"name": "Course 2",
"_id": {
"_id": "5944d5bc32c6ae293017428a",
"__v": 0,
"name": "Course 2",
"info": "fubble rumble"
},
"daysPresent": [
"2017-06-17T07:09:48.662Z"
]
}
]
},
{
"_id": "5944d5bc32c6ae293017428c",
"__v": 0,
"name": "Ted",
"email": "ted@example.com",
"courses": []
}
]
答案 1 :(得分:0)
你可以定义的模式如下: -
var mongoose = require('mongoose');
var courseSchema = new mongoose.Schema({
name: String
});
var studentSchema = new mongoose.Schema({
name: String,
email: { type: String, unique: true},
phone: String,
gender: String,
age: String,
city: String,
street: String,
picture: String,
courses: [{
course:{type:mongoose.Schema.Types.ObjectId,ref:'courseSchema'},
isAttending:{type:Boolean ,default:false}
}],
subscriptionDays: Number,
daysPresent: [Date]
}, schemaOptions);
module.exports = mongoose.model('Student', studentSchema);
isAttending将解决您的问题,如果学生订阅3门课程并转到特定的一门课程,那么isAttending将为true,否则为false。
由于