Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get related items in keystone

Working on a project in KeystoneJS and I'm having trouble figuring out the mongoose relationship bit.

According to the keystone docs, let's say we have the following models: User and Post. Now a post has a relationship to a user, so I'll write:

Post.add({
    author: { type: Types.Relationship, ref: 'User' }
});

and then:

User.relationship({ path: 'posts', ref: 'Post', refPath: 'author' });

Now, I want to be able to see all posts related to that User without having to query for both a User and Posts. For example, if I queried for a user object I would like to be able to do user.posts and have access to those related posts. Can you do this with mongoose/keystone?

like image 558
Quentin Donnellan Avatar asked Jun 12 '14 13:06

Quentin Donnellan


1 Answers

As far as I understand, keystone's List Relationship has nothing to do with mongoose and querying. Instead, it is used by keystone's admin UI to build out the relationship queries before rendering them in the view. This said I would forget User.relationship(...); solving your problem, although you want it for what I just mentioned.

The following should work fine based on your schema, but only populates the relationship on the one side:

var keystone = require('keystone');
keystone.list('Post').model.findOne().populate('author', function (err, doc) {
  console.log(doc.author.name); // Joe
  console.log(doc.populated('author'));  // '1234af9876b024c680d111a1' -> _id
});

You could also try this the other way, however...

keystone.list('User').model.findOne().populate('posts', function (err, doc) {
  doc.posts.forEach(function (post) {
    console.log(post);
  });
});

...mongoose expects that this definition is added to the Schema. This relationship is added by including this line in your User list file:

User.schema.add({ posts: { type: Types.Relationship, ref: 'Post', many: true } })

After reading the keystone docs, this seems to be logically equivalent the mongoose pure way, User.schema.add({ posts: [{ type: Schema.Types.ObjectId, ref: 'Post' }] });. And now you are now maintaining the relationship on both lists. Instead, you may want to add a method to your keystone list.

User.schema.methods.posts = function(done){
  return keystone.list('Post').model.find()
    .where('author', this.id )
    .exec(done);
};

By adding a method to your User list, it saves you from persisting the array of ObjectIds relating the MongoDB document back to the Post documents. I know this requires a second query, but one of these two options look to be your best bet.

like image 60
Eat at Joes Avatar answered Nov 20 '22 13:11

Eat at Joes