引用单个表的多列 - Sails JS API 模型

Posted

技术标签:

【中文标题】引用单个表的多列 - Sails JS API 模型【英文标题】:Multiple columns referencing single table - Sails JS API Model 【发布时间】:2016-09-06 08:35:45 【问题描述】:

最近我开始学习 Sails JS,虽然它看起来非常有用(我不必自己构建 api?!)我正在测试风帆的当前小项目遇到了一些障碍。

我的主要职业是教师,整个项目的最终目标是列出学生、与他们合作良好的同伴 (friend_id) 以及与他们合作的学生不是(unfriend_id)。使用这些信息,加上他们当前的 GPA,我想通过其他一些算法来优化座位表。

第一部分,我需要从 Sails 数据服务器返回数据以同意我的要求。

我需要为sails 做的(我已经查看了一对多集合以及多对多和多对一的sails 文档,但这个问题似乎很特殊)是收集基于friend_idunfriend_id 列的用户的所有项目。

数据

This SqlFiddle 具有基本架构设置,其中包含一些虚拟数据,供每个人复制/粘贴并在需要时直接使用。

用户

CREATE TABLE `students` (
  `student_id` int(11) NOT NULL AUTO_INCREMENT,
  `student_first_name` varchar(200) NOT NULL,
  `student_last_name` varchar(255) NOT NULL,
  `student_home_phone` varchar(10) DEFAULT NULL,
  `student_guardian_email` varchar(255) DEFAULT NULL,
  `student_gpa` float NOT NULL DEFAULT '2',
  `class_id` tinyint(4) NOT NULL,
  UNIQUE KEY `student_id` (`student_id`)
);

关系

CREATE TABLE `relations` (
  `relation_id` int(11) NOT NULL AUTO_INCREMENT,
  `student_id` int(11) NOT NULL DEFAULT '100000',
  `friend_id` int(11) DEFAULT NULL,
  `unfriend_id` int(11) DEFAULT NULL,
  UNIQUE KEY `relation_id` (`relation_id`)
);

虚拟数据(忽略名称)

INSERT INTO `students` VALUES (1,'Paul','Walker','1112223333','fake@email.com',2,1),(2,'Vin','Diesel','1112223333','fake@email.com',3,1),(3,'That','One\'Guy','1112223333','fake@email.com',4,1),(4,'Not','Yuagin','1112223333','fake@email.com',2,1),(5,'Hei','Yu','1112223333','fake@email.com',2,1);
INSERT INTO `relations` VALUES (1,1,2,NULL),(2,2,1,NULL),(3,1,NULL,4),(4,4,NULL,1),(5,1,5,NULL),(6,5,1,NULL),(7,2,3,NULL),(8,3,2,NULL);

我尝试了类似以下的方法,但是当我运行此 api 时,两者都会返回一个空的 json 数组(在此之前,我至少会收到一个学生/关系列表,具体取决于我正在寻找的 api)。

Students.js

module.exports = 
 connection:'localmysql',
    schema: 'true',
    attributes: 
        student_id: 
            type: "integer",
            required: true,
            unique: true,
            primaryKey:true
        ,
        student_first_name:
            type:'string'
        ,
        student_last_name:
            type:'string'
        ,
        student_home_phone:
            type:'integer'
        ,
        student_guardian_email:
            type: 'email'
        ,
        class_id:
            type:'integer'
        ,
        friends:
            collection:'relationship',
            via:'student_friends'
        
    ,
    autoPK: false,
    autoCreatedAt: false,
    autoUpdatedAt: false

Relationship.js

module.exports = 
    connection:'localMysql',
    tableName:'relations',

    attributes: 
        relation_id:
            type: 'integer',
            required: true,
            unique: true,
            primaryKey:true
        ,
        student_id:
            type:'integer'
        ,
        friend_id:
            type:'integer'
        ,
        unfriend_id:
            type:'integer'
        ,
        student_friends:
            collection:'students',
            via:'student_id'
        
    ,
    autoPK: false,
    autoCreatedAt: false,
    autoUpdatedAt: false

我对现在发生的所有事情并不完全陌生,但我对 Node 和 Sails 还很陌生,我似乎只是摸不着头脑。如果我想要的不能通过集合模型完成,我将在哪里放置代码以使这些事务发生?我假设(但你知道他们说什么......)它会在StudentsController.js 文件中?

Tl;博士

我可以得到这个 MySQL 查询创建的行为吗:

select 
    s.*, group_concat(r.friend_id) as friends, group_concat(r.unfriend_id) as unfriends 
from 
    students s  
left join 
    relations r 
ON s.student_id = r.student_id
GROUP BY s.student_id;

使用 Sails JS 中的 collection 设置进行了复制?

如果没有,我应该将代码放在哪里手动完成? (假设它不是 StudentsController.js

更新

按照@Solarflare 的建议,我设法得到了一些更内联的东西,尽管这是一个非常艰难的开始。现在我得到一个名为“关系”的专栏,但里面什么都没有。这比以前我一无所获要好(因为返回的所有内容都是[])。但它是一个空数组。 (输出如下)。

注意:我从关系模型中删除了student_friends 声明。

我该如何解决这个问题?

[
  
    "relationships": [],
    "student_id": 1,
    "student_first_name": "Paul",
    "student_last_name": "Walker",
    "student_home_phone": "1112223333",
    "student_guardian_email": "fake@email.com",
    "class_id": 1
  ,
  
    "relationships": [],
    "student_id": 2,
    "student_first_name": "Vin",
    "student_last_name": "Diesel",
    "student_home_phone": "1112223333",
    "student_guardian_email": "fake@email.com",
    "class_id": 1
  ,
  
    "relationships": [],
    "student_id": 3,
    "student_first_name": "That",
    "student_last_name": "One'Guy",
    "student_home_phone": "1112223333",
    "student_guardian_email": "fake@email.com",
    "class_id": 1
  ,
  
    "relationships": [],
    "student_id": 4,
    "student_first_name": "Not",
    "student_last_name": "Yuagin",
    "student_home_phone": "1112223333",
    "student_guardian_email": "fake@email.com",
    "class_id": 1
  ,
  
    "relationships": [],
    "student_id": 5,
    "student_first_name": "Hei",
    "student_last_name": "Yu",
    "student_home_phone": "1112223333",
    "student_guardian_email": "fake@email.com",
    "class_id": 1
  
]

更新 #2

好吧,我只是在等待的时候搞砸了一些非常基本的工作。我进入Relationship.js 文件并将student_id 的定义更改为model:'students',via:'student_id',我至少可以获得给定学生的所有关系。它给了我正确的收藏,但我仍然想知道是否有更直接的方法来摆弄这个来获得我需要的东西。这是localhost:1337/students 现在的输出:

[
  
    "relationships": [
      
        "relation_id": 1,
        "friend_id": 2,
        "unfriend_id": null,
        "student_id": 1
      ,
      
        "relation_id": 3,
        "friend_id": null,
        "unfriend_id": 4,
        "student_id": 1
      ,
      
        "relation_id": 5,
        "friend_id": 5,
        "unfriend_id": null,
        "student_id": 1
      
    ],
    "student_id": 1,
    "student_first_name": "Paul",
    "student_last_name": "Walker",
    "student_home_phone": "1112223333",
    "student_guardian_email": "fake@email.com",
    "class_id": 1
  ,
  
    "relationships": [
      
        "relation_id": 2,
        "friend_id": 1,
        "unfriend_id": null,
        "student_id": 2
      ,
      
        "relation_id": 7,
        "friend_id": 3,
        "unfriend_id": null,
        "student_id": 2
      
    ],
    "student_id": 2,
    "student_first_name": "Vin",
    "student_last_name": "Diesel",
    "student_home_phone": "1112223333",
    "student_guardian_email": "fake@email.com",
    "class_id": 1
  ,
  
    "relationships": [
      
        "relation_id": 8,
        "friend_id": 2,
        "unfriend_id": null,
        "student_id": 3
      
    ],
    "student_id": 3,
    "student_first_name": "That",
    "student_last_name": "One'Guy",
    "student_home_phone": "1112223333",
    "student_guardian_email": "fake@email.com",
    "class_id": 1
  ,
  
    "relationships": [
      
        "relation_id": 4,
        "friend_id": null,
        "unfriend_id": 1,
        "student_id": 4
      
    ],
    "student_id": 4,
    "student_first_name": "Not",
    "student_last_name": "Yuagin",
    "student_home_phone": "1112223333",
    "student_guardian_email": "fake@email.com",
    "class_id": 1
  ,
  
    "relationships": [
      
        "relation_id": 6,
        "friend_id": 1,
        "unfriend_id": null,
        "student_id": 5
      
    ],
    "student_id": 5,
    "student_first_name": "Hei",
    "student_last_name": "Yu",
    "student_home_phone": "1112223333",
    "student_guardian_email": "fake@email.com",
    "class_id": 1
  
]

【问题讨论】:

看起来Through 可能是答案——我会尽快调查并更新进度 我在这里遇到了真正的问题 - 我可能对集合对象的工作方式有一个非常基本的误解,因为我什至无法获得所有用户关系的简单集合,更不用说收集了不同的集合取决于是否设置了friend_idunfriend_id a) 你的“关系”不是收藏品。朋友是其他学生的集合。使用:friends: collection: 'students', via: 'student_id' and unfriends: collection: 'students', via: 'student_id' b) 这是一条单向路径:如果 a 是 b 的朋友, b 还没有和 a 一起,所以在添加朋友时,您必须同时添加他们(如果您愿意)。 c)您不能/不应该使用您的表“关系”(例如,导致密钥错误)。只需使用 Student.js。要使用您的关系模型,您可以使用through,但那里没有集合。 我以前试过(全部)。什么都没有显示。 “Nothing”表示“没有学生”或“nothing”表示“没有关系”?你只招平学生吗?那么这是意料之中的。您必须先填充连接,它们是未知的(它不会使用您在关系表中的数据)。也许发布你的新模型,我相信你已经尝试了所有这些,但是除了你和你的朋友收藏之外的任何人都很难在你的硬盘上诊断它。 【参考方案1】:

好的,所以这里的全部内容非常简单,我将上面的代码并在这里和那里进行了一些更改,老实说,我并不认为它会起作用,但我得到了更好的 一些东西比我以前得到的所有东西都多。这不是一个完美的解决方案,但目前它运行良好。

这是文件,以及我所做的:

Students.js

module.exports = 
    connection: 'localMysql',
    autoPK: false,
    autoCreatedAt: false,
    autoUpdatedAt: false,
    attributes: 
        student_id: 
            type: "integer",
            required: true,
            unique: true,
            primaryKey: true
        ,
        student_first_name: 
            type: 'string'
        ,
        student_last_name: 
            type: 'string'
        ,
        student_home_phone: 
            type: 'integer'
        ,
        student_guardian_email: 
            type: 'email'
        ,
        class_id: 
            type: 'integer'
        ,
        friends:
            collection:'relationship',
            via:'student_id'
        ,
        unfriends:
            collection:'relationship',
            via:'student_id'
        
    

;

Relationship.js

module.exports = 
    connection: 'localMysql',
    autoPK: false,
    autoCreatedAt: false,
    autoUpdatedAt: false,
    tableName:'relations',
    attributes: 
        relation_id: 
            type: 'integer',
            required: true,
            unique: true,
            primaryKey: true
        ,
        student_id: 
            model:'students',
            via:'student_id'
        ,
        friend_id: 
            model:'students',
            via:'student_id',
            through:'friends'
        ,
        unfriend_id: 
            model:'students',
            via:'student_id',
            through:'unfriends'
        

    
;

然后我在api/models/ 目录中添加了两个新文件Friends.jsUnfriends.js,它们都很简单:

Friends.js

module.exports = 
    connection: 'localMysql',
    schema: false,
    autoPK: false,
    autoCreatedAt: false,
    autoUpdatedAt: false,
    attributes: 
        student_id:
            model:'students',
            via:'student_id'
        ,
        friend_id:
            model:'relationship',
            via:'friend_id'
        
    

;

Unfriends.js

module.exports = 
    connection: 'localMysql',
    schema: false,
    autoPK: false,
    autoCreatedAt: false,
    autoUpdatedAt: false,
    attributes: 
        student_id:
            model:'students',
            via:'student_id'
        ,
        unfriend_id:
            model:'relationship',
            via:'unfriend_id'
        
    

;

输出

最重要的是“我得到了正确的输出吗”,简短的回答是:不,但它是可用的。我还没有得到原始查询的 Sails 表示,但我已经接近了。

localhost:1337/relationship 的输出

[
  
    "student_id": 
      "student_id": 1,
      "student_first_name": "Paul",
      "student_last_name": "Walker",
      "student_home_phone": "1112223333",
      "student_guardian_email": "fake@email.com",
      "class_id": 1
    ,
    "friend_id": 
      "student_id": 2,
      "student_first_name": "Vin",
      "student_last_name": "Diesel",
      "student_home_phone": "1112223333",
      "student_guardian_email": "fake@email.com",
      "class_id": 1
    ,
    "relation_id": 1
  ,
  
    "student_id": 
      "student_id": 1,
      "student_first_name": "Paul",
      "student_last_name": "Walker",
      "student_home_phone": "1112223333",
      "student_guardian_email": "fake@email.com",
      "class_id": 1
    ,
    "unfriend_id": 
      "student_id": 4,
      "student_first_name": "Not",
      "student_last_name": "Yuagin",
      "student_home_phone": "1112223333",
      "student_guardian_email": "fake@email.com",
      "class_id": 1
    ,
    "relation_id": 3
  , 
//Truncated for space

localhost:1337/students/的输出

[
  
    "friends": [
      
        "relation_id": 1,
        "student_id": 1,
        "friend_id": 2,
        "unfriend_id": null
      ,
      
        "relation_id": 3,
        "student_id": 1,
        "friend_id": null,
        "unfriend_id": 4
      ,
      
        "relation_id": 5,
        "student_id": 1,
        "friend_id": 5,
        "unfriend_id": null
      
    ],
    "unfriends": [
      
        "relation_id": 1,
        "student_id": 1,
        "friend_id": 2,
        "unfriend_id": null
      ,
      
        "relation_id": 3,
        "student_id": 1,
        "friend_id": null,
        "unfriend_id": 4
      ,
      
        "relation_id": 5,
        "student_id": 1,
        "friend_id": 5,
        "unfriend_id": null
      
    ],
    "student_id": 1,
    "student_first_name": "Paul",
    "student_last_name": "Walker",
    "student_home_phone": "1112223333",
    "student_guardian_email": "fake@email.com",
    "class_id": 1
  ,//Truncated for length

现在,在StudentsController.js 中,我完成了一个方法,它给了我更多我想要的东西。

StudentsController.js

module.exports = 
    get:function(req,res)
        Students.find()
                        .populate('friends', 
                                'friend_id':'!':null
                        )
                        .populate('unfriends',
                        'unfriend_id':'!':null
        ).exec(function(err,j)
            if(err) res.json(err);
            res.json(j);
        );
    
;

localhost:1337/students/get 的输出(这更接近我想要的 /students

[
  
    "friends": [
      
        "relation_id": 1,
        "student_id": 1,
        "friend_id": 2,
        "unfriend_id": null
      ,
      
        "relation_id": 5,
        "student_id": 1,
        "friend_id": 5,
        "unfriend_id": null
      
    ],
    "unfriends": [
      
        "relation_id": 3,
        "student_id": 1,
        "friend_id": null,
        "unfriend_id": 4
      
    ],
    "student_id": 1,
    "student_first_name": "Paul",
    "student_last_name": "Walker",
    "student_home_phone": "1112223333",
    "student_guardian_email": "fake@email.com",
    "class_id": 1
  ,
  
    "friends": [
      
        "relation_id": 2,
        "student_id": 2,
        "friend_id": 1,
        "unfriend_id": null
      ,
      
        "relation_id": 7,
        "student_id": 2,
        "friend_id": 3,
        "unfriend_id": null
      
    ],
    "unfriends": [],
    "student_id": 2,
    "student_first_name": "Vin",
    "student_last_name": "Diesel",
    "student_home_phone": "1112223333",
    "student_guardian_email": "fake@email.com",
    "class_id": 1
  //Truncated for length

现在为什么除了我在控制器中编写的代码之外的任何东西都表现得像现在这样,我不知道。但至少它是有效的。

【讨论】:

如果没有其他人能给我一个想法,我想我会得到我自己的赏金,这有点蹩脚。

以上是关于引用单个表的多列 - Sails JS API 模型的主要内容,如果未能解决你的问题,请参考以下文章

Sails js:如何在 Sails js 的单个模型中定义两个 MySQL 连接到两个不同的数据库?

如何在 Sails.js 中定义需要来自第三个模型/表的附加条件和/或数据的模型关联?

使用 passport.js、sails.js API 和 ember.js 登录 Facebook

基于MySql和Sails.js的RESTful风格的api实现

当从 android 访问 API 时,sails.js 会话变量会丢失

将哪些服务添加到sails.js 中的api/services 文件夹中