2016-07-02 4 views
1

я работаю с базой данных MongoDB, чьи коллекции модели классов, студентами, предметами и [академическая] производительностью. Ниже на основе схемы и Mongoose модели:Как обновить MongoDB документы с массивами поддокументов

var mongoose = require('mongoose'); 
var Schema = mongoose.Schema; 
var ObjectId = Schema.Types.ObjectId; 

// SUBJECT collection 
var subjectSchema = new Schema({ 
    name  : { type: String, required: true }, 
    category : { type: String, required: true } 
}); 
var Subject = mongoose.model('Subject', subjectSchema); 

// STUDENT collection 
var studentSchema = new Schema({ 
    name  : { type: String, required: true }, 
    grade  : { type: Number, required: true } 
}); 
var Student = mongoose.model('Student', studentSchema); 

// PERFORMANCE collection 
var performanceSchema = new Schema({ 
    subjectId : { type: ObjectId, ref: Subject.modelName, required: true }, 
    score  : { type: Number, required: true }, 
    maximum  : { type: Number, required: true }, 
    grade  : { type: String, required: true } 
}); 
var Performance = mongoose.model('Performance', performanceSchema); 

// *Note*: This is just to use as a sub-document schema, and not as a collection 
var classStudentSchema = new Schema({ 
    studentId : { type: ObjectId, ref: Student.modelName, required: true }, 
    performance : [performanceSchema] 
}, { _id: false }); 

// CLASS collection 
var classSchema = new Schema({ 
    name  : { type: String, required: true }, 
    scores  : [classStudentSchema] 
}); 
var Class = mongoose.model('Class', classSchema); 

документы class коллекций являются наиболее сложными из партии; пример документ будет:

{ 
    "_id" : ObjectId("57758f15f68da08c254ebee1"), 
    "name" : "Grade 5 - Section A", 
    "scores" : [{ 
    "studentId" : ObjectId("5776bd36ffc8227405d364d2"), 
    "performance": [{ 
     "subjectId" : ObjectId("577694ecbf6f3a781759c54a"), 
     "score" : 86, 
     "maximum" : 100, 
     "grade" : "B+" 
    }, { 
     "subjectId" : ObjectId("5776ffe1804540e29c602a62"), 
     "score" : 74, 
     "maximum" : 100, 
     "grade" : "A-" 
    }] 
    }, { 
    "studentId" : ObjectId("5776bd36ffc8227405d364d5"), 
    "performance": [{ 
     "subjectId" : ObjectId("577694ecbf6f3a781759c54a"), 
     "score" : 94, 
     "maximum" : 100, 
     "grade" : "A" 
    }, { 
     "subjectId" : ObjectId("5776ffe1804540e29c602a62"), 
     "score" : 81, 
     "maximum" : 100, 
     "grade" : "A" 
    }] 
    }] 
} 

я был в состоянии восстановить существующий класс документ и добавить студента это счеты, используя следующий код:

Class.findOne({ name: 'Grade 5 - Section A' }, function(err, class) { 
    if (err) throw err; 
    Student.findOne({ name: 'John Doe' }, function(err, student) { 
    if (err) throw err; 
    class.scores.push({ 
     studentId: student.id 
    }); 
    }; 
}); 

Но как добавить/обновить/удалить эта особенность студента? Мне нужно, чтобы иметь возможность взаимодействовать с class коллекции следующими способами:

  • Retrieve баллов для всех студентов, либо для конкретного студента (извлечения конкретного элемента в scores массиве)
  • Добавить/обновить/удалить счет конкретного студента, для конкретного субъекта (в случае обновления или удаления, получения определенного элемента в scores[n].performance массиве, для добавления, добавляемых в том же массиве

ответ

2

есть несколько способов сделать это. Я отвечу по пунктам

Получить баллы для всех студентов, либо для конкретного студента (получить конкретный элемент в массиве баллов)

Class.findOne({ name: 'Grade 5 - Section A'}) 
    .populate('scores.studentId') 
    .exec(function(err, class) { 
     if (err) throw err; 
     //now class.scores.studentId becomes ObjectStudent 
     //hence you have all scores for all students 
}); 

Добавить/обновить/удалить оценку конкретного студента, для конкретного субъекта (в случае обновления или удаления, получить определенный элемент в массиве [n] .performance; для добавления, добавьте к тому же массиву.

Class.findOneAndUpdate({name: 'Grade 5 - Section A' 
         ,'scores.studentId': ObjectId('5776bd36ffc8227405d364d2') 
         , 'scores.performance.subjectId' : ObjectId('577694ecbf6f3a781759c54a')} 
         , {$set: {scores.performance. score: 50}} 
         , function(err, data) { 
      if (err) throw err 
    }); 

Я надеюсь, что помогает

+0

Прежде всего, первая часть вашего ответа работал просто отлично. Я не совсем понимаю, как 'populate ('scores.studentId')' получает результаты для каждого ученика; кажется очень мощным. У меня есть некоторые вопросы: (а) как я могу получить оценку конкретного предмета для одного ученика? (b) Как добавить нового ученика в массив 'score? 'с пустым массивом' performance'? (c) Как добавить производительность для одного предмета для конкретного ученика? (d) и (e) аналогичны (b) и (c), но удаляются вместо добавления. Вы дали мне представление о том, как обновлять. Спасибо вам за помощь! –

+1

Не стоит беспокоиться о том, чтобы помочь. В конце дня минимальный документ, который вы можете вытащить, является классом. Если вы хотите вытащить отдельные поля, вы можете передать их в качестве второго параметра внутри find. findOneAndUpdate (query, {'scores.performance.grade': 1}, function (err) {}). Чтобы добавить баллы, просто используйте оператор «push» внутри модели mongoose, т. Е. Model.scores.push ({studentId: ObjectId ('xxxxxxxxx'), производительность: []}) или использовать поиск и обновление и использовать оператор $ push либо либо второй метод лучше, потому что это атомный. – Tim

+0

Могу ли я использовать populate для разрешения всех ссылок на внешние ключи по всей иерархии, за пределами 'scores.studentId'.Сделав это, я позволил ученику соответствовать ссылке «studentId» и аналогичным образом, я хочу, чтобы весь предметный документ соответствовал массиву 'subjectId' для каждого ученика' performance' массив? Моя цель - получить полностью ненормированный документ 'class', если я могу использовать этот термин в контексте MongoDB! –