Получить подробную информацию о связанной коллекции внутри другой коллекции с помощью populate () - PullRequest
0 голосов
/ 30 октября 2019

Я пытаюсь создать систему для записи расписаний. Для каждого дня сотрудник может записывать разные часы в зависимости от назначенных им различных задач. Каждая запись в моей коллекции расписаний содержит массив отдельных записей расписаний. Пример данных / схемы для этой коллекции:

[
    {
        "_id": "5db2c672620ed61854818ccd",
        "EmployeeId": "5da9aed442e3070bbd9f7581",
        "TimeSheet": [
            {
                "_id": "5db2c672620ed61854818ccf",
                "TaskId": "5db14152e6537a05258bf573",
                "Hours": "2.5",
                "Remarks": "Test 2.5"
            },
            {
                "_id": "5db2c672620ed61854818cce",
                "TaskId": "5db1886ee6537a05258bf575",
                "Hours": "11.5",
                "Remarks": "Test 11.5"
            }
        ],
        "__v": 0
    }
]

Для соответствующей коллекции задач данные располагаются следующим образом -

[
    {
        "_id": "5db14152e6537a05258bf573",
        "EmployeeId": "5da9aed442e3070bbd9f7581",
        "ProjectId": "5db141d9e6537a05258bf574",
        "TaskName": "Finish the timesheet page",
        "TaskDescription": "Write the front-end and back-end code to allow employees to record their timesheets."
    },
    {
        "_id": "5db1886ee6537a05258bf575",
        "EmployeeId": "5da9aed442e3070bbd9f7581",
        "ProjectId": "5db141d9e6537a05258bf574",
        "TaskName": "Learn Populate",
        "TaskDescription": "Learn how MongoDB/Mongoose uses the equivalent of SQL joins"
    },
    {
        "_id": "5db27e3ca2445c05255dbad0",
        "EmployeeId": "5da9aed442e3070bbd9f7581",
        "ProjectId": "5db141d9e6537a05258bf574",
        "TaskName": "Timesheet save API",
        "TaskDescription": "Code the API to save a timesheet to the database"
    }
]

Я пытаюсь получить сведения о задаче (TaskName, TaskDescription и др.) В каждую отдельную запись в расписании задач. Для этого я попытался использовать метод populate() в своем контроллере, например:

exports.findByEmployee = (req, res) => {
    TimeSheet.find({ EmployeeId: req.query.EmployeeId })
        .then(timesheets => {
            timesheets.forEach((ts, ts_index) => {
                ts.TimeSheet.forEach((item, index) => {
                    Task.findById(item.TaskId).populate('TaskId').exec((err, taskDetails) => {
                        item.TaskDetails = taskDetails;
                    })
                });
            })

            res.send(timesheets);

        }).catch(err => {
            res.status(500).send({
                message: err.message || "Some error occurred while retrieving timesheets."
            });
        });
}

Однако ответ API (для получения всех расписаний) не содержит ключ под названием TaskDetails в отдельном человеке. раздел расписания задач. Я предполагаю, что из-за асинхронного характера вызовов функций, часть res.send(timesheets) запускается до того, как секция выше успела закончить. Итак, мой вопрос, как мне это исправить? Подводя итог, я хочу, чтобы сведения о задании из коллекции заданий содержали каждый отдельный элемент расписания, связанный с заданием по идентификатору. Кроме того, это правильный способ использования populate(), или есть лучший / более простой / более правильный способ, который решит мою проблему?

РЕДАКТИРОВАТЬ: Кто-то запросил модели, поэтому вот задача и расписание:

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

const TaskSchema = mongoose.Schema({
    EmployeeId: ObjectId,
    ProjectId: ObjectId,
    TaskName: String,
    TaskDescription: String
}, { collection: 'TASK' });

module.exports = mongoose.model('Task', TaskSchema);
const mongoose = require('mongoose');
var ObjectId = mongoose.Schema.Types.ObjectId;

const TimeSheetSchema = mongoose.Schema({
    EmployeeId: ObjectId,
    Date: Date,
    TimeSheet: [
        {
            TaskId: {
                type: ObjectId,
                ref: 'TASK'
            },
            Hours: String,
            Remarks: String
        }
    ]
}, { collection: 'EMPLOYEE_TIMESHEET' });

module.exports = mongoose.model('TimeSheet', TimeSheetSchema);

1 Ответ

1 голос
/ 30 октября 2019

Здесь происходит несколько вещей. 1) TaskId не существует в коллекции Task, поэтому заполнение не работает (и нет необходимости использовать его там) 2) объект item, который вы объявляете в вашем ts.TimeSheet.forEach(), не будет существовать вне этогоЦикл forEach (), поэтому добавление taskDetails к нему ничего не дает, потому что объект item уничтожается при завершении цикла forEach ().

Я считаю, что то, что вы хотите, выглядит примерно так:

exports.findByEmployee = (req, res) => {
  try {
    // returns just the TimeSheet object from within the TimeSheet collection 
    // (recommend renaming one of these to avoid confusion!)
    TimeSheet.find({ EmployeeId: req.query.EmployeeId }, 'TimeSheet')
      // populates TaskId (which I recommend renaming 'Task') 
      // with the details from the Task collection
      .populate('TimeSheet.TaskId')
      // executes the query
      .exec(timesheets => {
        // sends the object once the query has finished executing
        res.send(timesheets);
      });
  } catch (err) {
    res.status(500).send({
      message: err.message || 'Some error occurred while retrieving timesheets.',
    });
  }
};

Я очень рекомендую руководство по экспресс-работе с локальной библиотекой MDN для хорошего знакомства с MongoDB и Mongoose.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...