один ко многим с мангустом

Я хочу определить отношение «один ко многим» между моей моделью ученика и моей моделью образования: 1 ученик принадлежит 1 формации, и формация может состоять из N студентов.

Мои потребности:

  • иметь возможность заполнять документ Formation своими учениками
  • легко получить образование студента

Итак, я написал:

let student = new Schema({
    firstName: {
        type: String
    },
    lastName: {
        type: String
    },
    formation : {
        type: Schema.Types.ObjectId,
        ref: 'Formation'
    }
});

let formation = new Schema({
    title: {
        type: String
    },
    students: [{ type: Schema.Types.ObjectId, ref: 'Student' }]
}

Когда я ищу документацию об отношении один-ко-многим с mongodb / mongoose, я с удивлением обнаруживаю, что когда я хочу создать документ Student (и добавить его в формирование), я должен не только установить его поле "формация" с идентификатором образования, а также вставьте его в поле документа формирования "студенты".
Означает ли это, что когда я хочу заменить формирование студента другой формацией, мне нужно будет 1 / обновить его поле формирования 2 / удалить себе идентификатор студента из поля формации "студенты" и повторно добавить его в поле студентов новой формации?
Мне это кажется немного избыточным. Я что-то упускаю?


person Guid    schedule 27.10.2015    source источник


Ответы (2)


Наличие students в модели формирования - плохая практика и избыточность. Потенциально бесконечные массивы - плохая конструкция, поскольку они могут привести к превышению предельных размеров документа. Что касается избыточности, в этой ситуации у вас есть только два запроса:

1) У вас в памяти есть student, и вы хотите найти их образование:

Formation.findOne({_id: student.formation},callback);

2) У вас есть formation в памяти, и вы хотите найти всех учеников в этой формации:

Student.find({formation: formation._id}, callback);

Ни то, ни другое не требует наличия students в схеме формирования.

person chrisbajorin    schedule 27.10.2015
comment
Это работает, но поиск в коллекции учеников для каждого ученика с заданным идентификатором формации происходит намного медленнее, чем поиск данной формации и возвращение массива студентов, если предполагается, что студентов больше, чем формаций. - person awimley; 27.10.2015
comment
Если формация проиндексирована, вы действительно только занимаетесь микрооптимизацией, а не правильным дизайном. - person chrisbajorin; 27.10.2015
comment
Верно, что это актуально только для большой базы данных. Не могли бы вы оправдать то, что вы называете правильным дизайном? - person awimley; 27.10.2015
comment
Из-за того, что операции с несколькими документами не являются атомарными, обновление информации в двух местах может сделать ваши данные несовместимыми. Поэтому, если вы храните одну и ту же информацию в двух местах и ​​что-то ломается в середине обновления, ваши данные не совпадают. У вас должны быть задачи, которые запускаются с перерывами, чтобы ваши данные в конечном итоге были согласованными. - person chrisbajorin; 27.10.2015
comment
О, я думаю, у нас возникло недоразумение. Я имел в виду для студентов как свойство формаций или наоборот. Очевидно, что иметь и то и другое - плохая практика. - person awimley; 27.10.2015
comment
Ой, попался. Причина в том, что это именно один ко многим. Наличие ученика в составе группы не ограничивает его присутствие где-либо еще. formation.findOne({students: student._id}) потенциально может найти не тот, если они попали в два. Он просто получает первый результат в порядке сортировки. - person chrisbajorin; 27.10.2015
comment
Ваше обсуждение научило меня более 2 недель просмотра веб-страниц. Большое спасибо. - person Guid; 27.10.2015

Фактически, это избыточно, потому что способ, которым вы определили свои схемы, является избыточным. Массив студентов должен быть свойством образования, но не наоборот. Поддокументы можно искать как в обычных коллекциях. Если вы измените свою схему на:

let student = new Schema({
    firstName: {
        type: String
    },
    lastName: {
        type: String
    }
});

let formation = new Schema({
    title: {
        type: String
    },
    students: [{ type: Schema.Types.ObjectId, ref: 'Student' }]
}

Вы должны уметь выполнять свои задачи с помощью довольно коротких команд. Предполагая, что формации и студенты - это имена вашей коллекции:

1: Создание студента и сохранение документов об образовании и студента.

var stud = new student({name: "Sally"}); //Assuming you modeled to student
stud.save(function (err, student) {
  formations.findOne({}, function (err, form) { //Dont know how you find formations, I assume you know
    form.students.push(stud._id);
    form.save(callback);
  }  
});

2. Получение формирования студента с заданным ID:

formations.findOne({"students" : { $elemMatch: {_id: id}}}, function (err, doc) {})
  1. Даже переместить студента относительно просто.

    formNew.students.push (

formOld.students.pop(formOld.students.indexOf(formOld.students.findOne( //elemMatch like above )))

Извините за странное форматирование.

person awimley    schedule 27.10.2015