Node.js 改进课程订阅应用程序的Mongoose模式

Node.js 改进课程订阅应用程序的Mongoose模式,node.js,mongodb,mongoose,Node.js,Mongodb,Mongoose,我是mongodb的新手,正在玩一个自助项目,用户可以订阅3-4个预定义的不同课程。每门课程每天1小时,学生可以订阅15天、30天或更长的时间 该应用程序将存储学生的信息、他们订阅的课程以及他们参加课程的天数 这是我的猫鼬模式 var mongoose = require('mongoose'); var schemaOptions = { timestamps: true, toJSON: { virtuals: true } }; var courseSchema =

我是mongodb的新手,正在玩一个自助项目,用户可以订阅3-4个预定义的不同课程。每门课程每天1小时,学生可以订阅15天、30天或更长的时间

该应用程序将存储学生的信息、他们订阅的课程以及他们参加课程的天数

这是我的猫鼬模式

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);
在这里,课程是3-4门课程中的任意一门,一个学生可以同时订阅一门或多门课程。subscriptionDays是他们订阅课程的天数,daysPresent是他们参加课程的天数

我不确定这是否是我的项目的正确模式,到目前为止,我能够做到这一点

与模式的混淆包括:

当订阅两门不同课程的学生到达 学院,但只修一门课,那我就不这么认为了 schema支持这种情况,为此我想修改courseSchema如下

var courseSchema = new mongoose.Schema({
  name: String,
  subsriptionDays: Number,
  daysPresent: [Date]
});
但是,在这样做之后,我仍然对数据的更改感到困惑,比如每次学生参加课程时都必须将日期插入文档中

第二个困惑是我如何每天更新文档中的数据,只有每天必须插入的数据才是天内的日期。
我能从Mongo专家那里得到一些指导和建议吗?TIA

模式您可以定义如下:-

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);
如果学生订阅了3门课程并选择了某一门课程,那么isAttending将解决您的问题,否则isAttending将为真,否则为假

您可以使用npm模块,它将在您设定的时间运行一个函数,并使您的生活变得轻松。
谢谢

我认为您对扩展设计的第二个想法基本上是正确的。我只想通过包含对课程本身的引用,而不仅仅是模式中嵌入的信息,来扩展这一点

对于您的用例问题,最好通过一个工作示例来解决:

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功能的两门课程的添加。为了确保您没有添加已经存在的课程,如果课程数组中已经存在所选课程,则查询表达式实际上会排除所选课程。在本例中,传递了一个列表,因此我们使用,但对于单个项目,您只需使用:

添加出席日期这实际上演示了一种情况,即您希望在课程中按位置匹配项目,以便知道要更新哪个项目。这是通过提供一个与之前非常相似的匹配条件来实现的,而不是排除特定的数组元素。然后在实际更新部分中,我们应用相同的运算符,以便可以附加到daysPresentarray,但也可以使用positional$运算符指向与匹配条件对应的正确数组索引位置:

{ "email": "bill@example.com", "courses.name": 'Course 2' },
{ "$push": { "courses.$.daysPresent": new Date() } },
另外,还有一些操作显示了在他们自己的集合中保留课程列表与您可能不想在每个学生身上嵌入的其他信息之间的关系

示例中的最后一个操作实际上执行了.populate以实际从其他集合中提取此信息以进行显示

整个示例已使用mongoose打开调试;因此,您可以看到对MongoDB的实际调用对每个操作的实际作用

还要熟悉这里使用的方法,以及核心MongoDB文档中的各种方法

样本输出
哇!谢谢你这样一个描述性的回答,你的回答对我来说几乎没有什么新的东西,我现在肯定会学习它们。我可以说,这就是我想要的答案。你能给我一个关于async.series内部代码的演练吗?我试过了,但无法理解。@LuzanBaral这里的列表中,它实际上只是一个例子,所有的库调用都是这样。所以这只是一种方便,而不是一种要求。大部分工作都可以通过简单的承诺或定期的回调嵌套来完成。特别是,一个序列一个接一个地执行,瀑布从序列中传入。对于另一个问题本身来说,这是一个更广泛的话题。但是你有文档链接,还有“承诺立即搜索”等术语。@LuzanBaral如果你还有其他问题,那么这就是本网站的目的。在你发布新问题之前,请在这里搜索可能很好地解决你的问题的示例甚至其他答案。
{ "email": "bill@example.com", "courses.name": 'Course 2' },
{ "$push": { "courses.$.daysPresent": new Date() } },
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": []
  }
]