改进课程订阅应用程序的Mongoose Schema

时间:2017-06-17 02:25:00

标签: node.js mongodb mongoose

我是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

2 个答案:

答案 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。

  • 您可以使用Cron npm模块,该模块将在您设置的时间运行功能,让您的生活变得轻松。

由于