Reputation: 1427
Using sails.js v0.10.0-rc7, I would like to save a user and his friends.
I guess I need to somehow create a many-to-many association from a model to itself? Is it possible?
User.js:
module.exports = {
attributes: {
name: {
type: 'string'
},
friends: {
collection: 'user',
via: ?
}
}
};
I'm using sails-mysql if it matters. I found this question, which is relevant but didn't solve my problem: https://github.com/balderdashy/waterline/issues/410
Thanks!
Update: So far I found two ways of doing this, but both uses redundant data:
As suggested by hansmei:
module.exports = {
attributes: {
id:{
type: 'integer',
autoIncrement: true,
primaryKey: true
},
name: {
type: 'string'
},
friends: {
collection: 'user',
via: 'id'
}
}
}
Which requires me to save each friendship twice:
User.findOne(1).exec(function (err, user) {
user.friends.add(2);
...
User.findOne(2).exec(function (err, user) {
user.friends.add(1);
...
attributes: {
name: {
type: 'string'
},
friends: {
collection: 'user',
via: 'friendOf',
dominant: true
},
friendOf:{
collection:'user',
via:'friends'
}
}
Which is also redundant, because friendship is always mutual.
(If user A is friend of user B, then user B must be a friend of user A)
Any suggestions?
Upvotes: 2
Views: 2747
Reputation: 1751
This is a problem I wanted to solve in my Backbone.Sails plugin (until Waterline sorts it out).
I have completely rewritten the Sails blueprints, including support for self referencing many to many associations. In the model definition, you simply need to adopt the conventions required:
/api/models/Person.coffee
module.exports =
attributes:
friends:
collection: "person"
via: "_friends"
dominant: true
_friends:
collection: "person"
via: "friends"
Above, the friends
attribute is the collection to be persisted. When persisting via the blueprints, the _friends
collection will mirror that of the friends
collection, mimicing any add or remove requests made - which means the friends
collection will be a mutual relation without any extra code needed client side.
You can download the blueprints here. They'll work fine without the front-end part of this plugin (though you will need to compile them or npm install coffee-script
). Just include them in your /api/blueprints folder and sails (0.10) will pick them up.
Whilst I appreciate this solution is far from ideal, it seems to be the best one for the time being (especially if you use blueprints for all your persistence). A better workaround would be the life-cycle callbacks - but they don't apply to the .add(id)
and .remove(id)
functions.
Upvotes: 0
Reputation: 701
I've managed to make associations to self in this way (at least for local disk storage). It should work for MySQL as well.
User model:
module.exports = {
attributes: {
id:{
type: 'integer',
autoIncrement: true,
primaryKey: true
},
name: {
type: 'string'
},
friends: {
collection: 'user',
via: 'id'
}
}
}
I'm not sure if it's a valid many-to-many relationship, but I think you can tweak it to make it work for you:)
Upvotes: 4