Get related items in keystone
Asked Answered
S

2

6

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?

Sexpot answered 12/6, 2014 at 13:58 Comment(0)
E
4

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.

Embank answered 16/6, 2014 at 23:10 Comment(1)
Seems KeystoneJS v5 has no model.find() methods, any update?Tedford
S
0

I found this on their github https://github.com/Automattic/mongoose/issues/1888, check it for context, but basically says to use the keystone populateRelated() method. I tested it and does work

// if you've got a single document you want to populate a relationship on, it's neater
Category.model.findOne().exec(function(err, category) {
  category.populateRelated('posts', function(err) {
    // posts is populated
  });
});

I'm aware the question is old but this has to be out there for further reference

Sailcloth answered 29/3, 2016 at 2:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.