I'm new to Sails.js (v0.10.5) and Waterline ORM. I have 3 tables in database: users (id, name), roles(id, alias) and join table users_roles(user_id, role_id). It's important not to change table names and field names in database. I want Policy entity to be a join entity between User and Role. Here is some mapping code:
//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'
}
}
}
But when I trying to access roles atribute in controller
User.findOne({id: 1}).populate('roles').exec(function(err, user) {
console.log(JSON.stringify(user.roles));
});
this returns
[]
And
User.findOne({id: 1}).populate('roles').exec(function(err, user) {
console.log(JSON.stringify(user));
});
returns
{"id":1,"name":"test", "roles":[]}
I checked twice that user, role and association between them exists in database. What is my mistake?
Waterline is a next-generation storage and retrieval engine, and the default ORM used in the Sails framework. It provides a uniform API for accessing stuff from different kinds of databases and protocols.
populate() Modify a query instance so that, when executed, it will populate child records for the specified collection, optionally filtering by subcriteria . Populate may be called more than once on the same query, as long as each call is for a different association.
I have found way to solve this problem. It's not what I exactly want, but it works. First: join entity:
//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;
});
}
}
As you see, I added ID field to this entity (and to db table users_roles too), so it's not the great solution.
//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'
}
}
}
And Role Entity:
//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'
}
}
}
That's how I get all roles for specified 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');
}
});
...
Maybe it'll be usefull for somebody =)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With