Sails.js + Waterline:通过关联进行多对多

Posted

技术标签:

【中文标题】Sails.js + Waterline:通过关联进行多对多【英文标题】:Sails.js + Waterline: Many-to-Many through association 【发布时间】:2014-11-19 09:22:06 【问题描述】:

我是 Sails.js (v0.10.5) 和 Waterline ORM 的新手。我在数据库中有 3 个表:用户(id,名称),角色(id,别名)和连接表 users_roles(user_id,role_id)。重要的是不要更改数据库中的表名和字段名。我希望策略实体成为用户和角色之间的连接实体。这是一些映射代码:

//User.js
module.exports = 
    tableName: 'users',
    autoCreatedAt: false,
    autoUpdatedAt: false,
    attributes: 
        id: 
            type: 'integer',
            required: true
        ,
        name: 
            type: 'string'
        ,
        roles: 
            collection: 'role',
            via: 'users',
            through: 'policy'
        ,
    


//Role.js
module.exports = 
    tableName: "roles",
    autoCreatedAt: false,
    autoUpdatedAt: false,
    attributes: 
        id: 
            type: 'integer',
            required: true
        ,
        alias: 
            type: 'string',
            required: true
        ,
        users: 
            collection: 'user',
            via: 'roles',
            through: 'policy'
        
    


//Policy.js
module.exports = 
    tableName: "users_roles",
    tables: ['users', 'roles'],
    junctionTable: true,
    autoCreatedAt: false,
    autoUpdatedAt: false,
    attributes: 
        user: 
            columnName: 'user',
            type: 'integer',
            foreignKey: true,
            references: 'user',
            on: 'id',
            via: 'role',
            groupBy: 'user'
        ,
        roles: 
            columnName: 'role',
            type: 'integer',
            foreignKey: true,
            references: 'role',
            on: 'id',
            via: 'user',
            groupBy: 'role'
        
    

但是当我尝试访问控制器中的角色属性时

User.findOne(id: 1).populate('roles').exec(function(err, user) 
    console.log(JSON.stringify(user.roles));
);

这会返回

[]

还有

User.findOne(id: 1).populate('roles').exec(function(err, user) 
    console.log(JSON.stringify(user));
);

返回

"id":1,"name":"test", "roles":[]

我检查了两次用户、角色和它们之间的关联是否存在于数据库中。我的错误是什么?

【问题讨论】:

你能把代码过去吗?确保您正在执行 User.find().populate('roles').exec(function()) @mandeep_m91 感谢您的回复!我编辑了问题(console.log 输出中有一些错误)。 你能解决这个问题吗?如果没有,您使用的是哪个底层数据库? @mandeep_m91 我已经解决了这个问题。我向 Policy 实体添加了一个 ID 字段,并将 User 和 Policy(以及 Role 和 Policy)之间的关联更改为 OneToMany。这不是我真正想要的,但它有效.. @mandeep_m91 我正在使用 postgresql 9.3 【参考方案1】:

我找到了解决这个问题的方法。这不是我真正想要的,但它有效。 第一:加入实体:

//Policy.js
module.exports = 
    tableName: "users_roles",
    autoPK: false,
    attributes: 
        id: 
            type: 'integer',
            primaryKey: true,
            autoIncrement: true,
        ,
        user: 
            columnName: 'user_id',
            model: 'user'
        ,
        role: 
            columnName: 'role_id',
            model: 'role'
        
    ,
    //tricky method to get all users for specified role_id
    //or to get all roles for specified user_id
    get: function(id, modificator, cb) 
        var fields = ['user', 'role'];
        if (fields.indexOf(modificator) < 0) 
            cb(new Error('No such modificator in Policy.get()'), null);
        
        var inversedField = fields[(fields.indexOf(modificator) + 1) % 2];
        var condition = ;
        condition[inversedField] = id;
        this.find(condition).populate(modificator).exec(function(err, policies) 
            if (err) 
                cb(err, null);
                return;
            
            var result = [];
            policies.forEach(function(policy) 
                result.push(policy[modificator]);
            );
            cb(null, result);
            return;
        );
    

如您所见,我将 ID 字段添加到该实体(以及 db 表 users_roles 中),所以这不是很好的解决方案。

//User.js
module.exports = 
    tableName: 'users',
    autoPK: false,
    attributes: 
        id: 
            type: 'integer',
            primaryKey: true,
            autoIncrement: true,
            unique: true,
        ,
        name: 
            type: 'string'
        ,
        policies: 
            collection: 'policy',
            via: 'user'
        
    

和角色实体:

//Role.js
module.exports = 
    tableName: 'roles',
    autoPK: false,
    attributes: 
        id: 
            type: 'integer',
            primaryKey: true,
            autoIncrement: true,
        ,
        alias: 
            type: 'string',
            required: true,
            unique: true,
        ,
        policies: 
            collection: 'policy',
            via: 'role'
        
    

这就是我获取指定 user_id 的所有角色的方式:

...
id = req.session.me.id; //user_id here
Policy.get(id, 'role', function(err, roles) 
    var isAdmin = false;
    roles.forEach(function(role) 
        isAdmin |= (role.id === 1);
    );
    if (isAdmin) 
        next(null);
        return;
     else 
        return res.redirect('/login');
               
);
...

也许它对某人有用 =)

【讨论】:

差不多 2 年后对我很有用!谢谢!

以上是关于Sails.js + Waterline:通过关联进行多对多的主要内容,如果未能解决你的问题,请参考以下文章

Sails.js / Waterline - 创建不是模型上的功能

Sails.js/waterline: groupBy + count

Sails.js Waterline ORM:.findOrCreate() 没有 .populate() 方法

在视图中显示一对多关系sails.js waterline orm的列表

Sails.Js - 我如何在sails.Js 中进行分页

Sails.js 使用sails-mysql 的日期的水线查询修饰符?