Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sails.js Same Model many to many association

Sails.js .10 rc8

I've completely run out of ideas for this

I have a model called User and I want to associate it in a collection to other users like a friends list. Like a many-to-many association

   //User.js
   friends: {
     collection: 'user',
     via: 'friends'
   }

but when I run .populate('friends') it doesn't populate anything. Any ideas?

like image 345
scott Avatar asked Oct 07 '14 03:10

scott


2 Answers

I find that the best way to implement this is actually adding a reference to the id.

Check this User model:

module.exports = {
  attributes: {
    name: {
      type: 'string',
      required: true,
      minLength: 2
    },
    email: {
      type: 'email',
      required: true,
      unique: true
    },
    friends: {
      collection: 'user',
      via: 'id'
    }
  }
};

Now, if you run sails console you can test the following commands:

User.create({name:'test',email:'[email protected]'}).exec(console.log);

It returns:

{ name: 'test',
  email: '[email protected]',
  createdAt: '2016-12-01T22:06:19.723Z',
  updatedAt: '2016-12-01T22:06:19.723Z',
  id: 1 }

You created your first user. Lets create some other ones:

User.create({name:'test2',email:'[email protected]'}).exec(console.log);

Resulting in:

 { name: 'test2',
  email: '[email protected]',
  createdAt: '2016-12-01T22:06:40.808Z',
  updatedAt: '2016-12-01T22:06:40.808Z',
  id: 2 }

Let's see what we have so far:

User.find().populate('friends').exec(console.log);

[ { friends: [],
    name: 'test',
    email: '[email protected]',
    createdAt: '2016-12-01T22:06:19.723Z',
    updatedAt: '2016-12-01T22:06:19.723Z',
    id: 1 },
  { friends: [],
    name: 'test2',
    email: '[email protected]',
    createdAt: '2016-12-01T22:06:40.808Z',
    updatedAt: '2016-12-01T22:06:40.808Z',
    id: 2 } ]

Now, let's create a user with a friend, using the reference to the first user. Notice that I just pass a single id, not an array:

User.create({name:'test3',email:'[email protected]', friends:1}).exec(console.log);

Now, the result is this one. Notice that "friends" does not appear. This is by design.

{ name: 'test3',
  email: '[email protected]',
  createdAt: '2016-12-01T22:07:34.988Z',
  updatedAt: '2016-12-01T22:07:34.994Z',
  id: 3 }

Let's do a find with populate to see the current status:

User.find().populate('friends').exec(console.log);

Now we see that the third user has friends. The others have an empty array.

 [ { friends: [],
    name: 'test',
    email: '[email protected]',
    createdAt: '2016-12-01T22:06:19.723Z',
    updatedAt: '2016-12-01T22:06:19.723Z',
    id: 1 },
  { friends: [],
    name: 'test2',
    email: '[email protected]',
    createdAt: '2016-12-01T22:06:40.808Z',
    updatedAt: '2016-12-01T22:06:40.808Z',
    id: 2 },
  { friends: 
     [ { name: 'test',
         email: '[email protected]',
         createdAt: '2016-12-01T22:06:19.723Z',
         updatedAt: '2016-12-01T22:06:19.723Z',
         id: 1 } ],
    name: 'test3',
    email: '[email protected]',
    createdAt: '2016-12-01T22:07:34.988Z',
    updatedAt: '2016-12-01T22:07:34.994Z',
    id: 3 } ]

Let's create a fourth one, this time with two friends:

User.create({name:'test4',email:'[email protected]', friends:[1,2]}).exec(console.log);

Resulting in (again, no friends property):

 { name: 'test4',
  email: '[email protected]',
  createdAt: '2016-12-01T22:07:50.539Z',
  updatedAt: '2016-12-01T22:07:50.542Z',
  id: 4 }

This time, we passed an array of ids to friends. Let's see the current status:

User.find().populate('friends').exec(console.log);

 [ { friends: [],
    name: 'test',
    email: '[email protected]',
    createdAt: '2016-12-01T22:06:19.723Z',
    updatedAt: '2016-12-01T22:06:19.723Z',
    id: 1 },
  { friends: [],
    name: 'test2',
    email: '[email protected]',
    createdAt: '2016-12-01T22:06:40.808Z',
    updatedAt: '2016-12-01T22:06:40.808Z',
    id: 2 },
  { friends: 
     [ { name: 'test',
         email: '[email protected]',
         createdAt: '2016-12-01T22:06:19.723Z',
         updatedAt: '2016-12-01T22:06:19.723Z',
         id: 1 } ],
    name: 'test3',
    email: '[email protected]',
    createdAt: '2016-12-01T22:07:34.988Z',
    updatedAt: '2016-12-01T22:07:34.994Z',
    id: 3 },
  { friends: 
     [ { name: 'test',
         email: '[email protected]',
         createdAt: '2016-12-01T22:06:19.723Z',
         updatedAt: '2016-12-01T22:06:19.723Z',
         id: 1 },
       { name: 'test2',
         email: '[email protected]',
         createdAt: '2016-12-01T22:06:40.808Z',
         updatedAt: '2016-12-01T22:06:40.808Z',
         id: 2 } ],
    name: 'test4',
    email: '[email protected]',
    createdAt: '2016-12-01T22:07:50.539Z',
    updatedAt: '2016-12-01T22:07:50.542Z',
    id: 4 } ]

Now, how do you add a friend to an existing user? It's somehow odd: you have to first find the user, then use the add function on the resulting model, and then, save it. In my day to day code, I have a helper function that does just that. So, here is the example:

User.findOne(1).populate('friends').exec(function(err,u){ u.friends.add(3);u.save(function(err){ if(err) console.error(err);});});

Now in the console we see no results. Let's check the User content now:

User.find().populate('friends').exec(console.log);

[ { friends: 
     [ { name: 'test3',
         email: '[email protected]',
         createdAt: '2016-12-01T22:07:34.988Z',
         updatedAt: '2016-12-01T22:07:34.994Z',
         id: 3 } ],
    name: 'test',
    email: '[email protected]',
    createdAt: '2016-12-01T22:06:19.723Z',
    updatedAt: '2016-12-01T22:09:41.410Z',
    id: 1 },
  { friends: [],
    name: 'test2',
    email: '[email protected]',
    createdAt: '2016-12-01T22:06:40.808Z',
    updatedAt: '2016-12-01T22:06:40.808Z',
    id: 2 },
  { friends: 
     [ { name: 'test',
         email: '[email protected]',
         createdAt: '2016-12-01T22:06:19.723Z',
         updatedAt: '2016-12-01T22:09:41.410Z',
         id: 1 } ],
    name: 'test3',
    email: '[email protected]',
    createdAt: '2016-12-01T22:07:34.988Z',
    updatedAt: '2016-12-01T22:07:34.994Z',
    id: 3 },
  { friends: 
     [ { name: 'test',
         email: '[email protected]',
         createdAt: '2016-12-01T22:06:19.723Z',
         updatedAt: '2016-12-01T22:09:41.410Z',
         id: 1 },
       { name: 'test2',
         email: '[email protected]',
         createdAt: '2016-12-01T22:06:40.808Z',
         updatedAt: '2016-12-01T22:06:40.808Z',
         id: 2 } ],
    name: 'test4',
    email: '[email protected]',
    createdAt: '2016-12-01T22:07:50.539Z',
    updatedAt: '2016-12-01T22:07:50.542Z',
    id: 4 } ]

With this method, you can even add the same user to the friends collection!

User.findOne(1).populate('friends').exec(function(err,u){ u.friends.add(1);u.save(function(err){ if(err) console.error(err);});});

Have fun!

like image 66
Luis Lobo Borobia Avatar answered Oct 12 '22 13:10

Luis Lobo Borobia


Your models should look like this...

//User.js
friends: {
  collection: 'friend',
  via: 'user'
}

//Friend.js
user: {
  model: 'user'
  via: 'friends'
}

Also sails 10 rc8 is old. You should be on sails 10.5

like image 34
InternalFX Avatar answered Oct 12 '22 13:10

InternalFX