Angularjs:通过关系的多对多

Angularjs: Many-to-Many with Through Relationship

在我的应用程序中,我有 学生 可以 Enroll Classes.

注册记录开始和结束日期以及Class

Class 包含详细信息,例如 class 名称和描述。

Student (1) - (N) Enrollment (1) - (1) Class

Therefore

Student (1) - (N) Class

这就是我希望对象的样子。

{
  "studentId": 1,
  "name": "Henrietta",
  "enrolledClasses": [
    {
      "enrollmentId": 12,
      "startDate": "2015-08-06T17:43:14.000Z",
      "endDate": null,
      "class": 
        { 
          "classId": 15,
          "name": "Algebra",
          "description": "..."
        }
    },
      "enrollmentId": 13,
      "startDate": "2015-08-06T17:44:14.000Z",
      "endDate": null,
      "class": 
        {
          "classId": 29,
          "name": "Physics",
          "description": "..."
        }
    }
}

但是我的 RESTful API 无法(轻松地)输出关系的完整嵌套结构,因为它的 ORM 不能通过关系实现多对多。所以我得到了学生和他们的多个注册,但只是对每个 class 的引用,而不是详细信息。我需要显示详细信息,而不仅仅是一个 Id。

我可以等待学生对象可用,然后使用引用为每个 classId 对 API 进行额外调用以获取详细信息,但我不确定如何,或者即使,然后将其与学生对象集成。

这是我目前所拥有的。

function findOne() {
  vm.student = StudentsResource.get({
    studentId: $stateParams.studentId
  });
};

这是我从 API

中得到的
{
  "studentId": 1,
  "name": "Henrietta",
  "enrolledClasses": [
    {
      "enrollmentId": 12,
      "startDate": "2015-08-06T17:43:14.000Z",
      "endDate": null,
      "class": 15
    },
      "enrollmentId": 13,
      "startDate": "2015-08-06T17:44:14.000Z",
      "endDate": null,
      "class": 29
    }
}

对于 class 的详细信息,我可以一次一个地添加它们,但还没有弄清楚如何等到学生对象可用时将它们推入其中。也不知道如何正确推动它们...

{ 
  "classId": 15,
  "name": "Algebra",
  "description": "..."
}

{
  "classId": 29,
  "name": "Physics",
  "description": "..."
}

问题

通过注册将学生和 class(es) 详细信息合并为一个对象是否是一种好的做法?

请记住,该应用程序将允许更改学生详细信息和注册,但不应允许更改 class 姓名或描述的详细信息。因此,如果 Angular 为对象发送 PUT,则不应尝试发送任何 class 的详细信息,而应仅发送参考。这将强制服务器端保护数据,但为避免错误,客户端不应尝试。

作为背景,我在后台使用 SailsJS 和 PostgreSQL API。

所以基本上在 Sailsjs 方面,您应该覆盖 StudentController.js 中的 findOne 函数。这是假设您使用的是蓝图。

// StudentController.js
module.exports = {
  findOne: function(req, res) {
    Student.findOne(req.param('id')).populate('enrollments').then(function(student){
      var studentClasses = Class.find({
        id: _.pluck(student.enrollments, 'class')
      }).then(function (classes) {
        return classes
      })
      return [student, classes]
    }).spread(function(student, classes){
      var classes = _.indexBy(classes, 'id')
      student.enrollments = _.map(student.enrollments, function(enrollment){
        enrollment.class = classes[enrollment.class]
        return enrollment
      })
      res.json(200, student)
    }).catch(function(err){
      if (err) return res.serverError(err)
    })
  }
}

// Student.js

module.exports = { 
  attributes: {
    enrollments: {
      collection: 'enrollment',
      via: 'student'
    } 
    // Rest of the attributes..   
  }
}

// Enrollment.js

module.exports = {
  attributes: {
    student: {
      model: 'student'
    }
    class: {
      model: 'class'
    }
    // Rest of the attributes...
  }
}

// Class.js

module.exports: {
  attributes: {
    enrollments: {
      collection: 'enrollment',
      via: 'class'
    }
    // Rest of the attrubutes
  }
}

说明:
1. 使用 Lo-dash 的 _.pluck 函数重新调整了一个 classId 数组,我们找到了我们想要填充的所有 classes。然后我们使用 promise 链 .spread(),创建一个由 classid 索引的数组,并将 classId 映射到我们想要填充到学生返回的注册中的实际 class 实例来自 Student.findOne()。
2. Return 入学率很高的学生 class.

来源:Sails.js populate nested associations