5

Does anyone have a good example of adding a name to a relationship field in keystonejs? Right now it just saves an id so if I need to display that fields name in a jade template I need to also query that relationship model. Ideally something like this:

var keystone = require('keystone'),
Types = keystone.Field.Types;

/**
 * Titles Model
 * =============
 */

var Title = new keystone.List('Title');

Title.add({
  name: { type: String, required: true, initial: true },
  room: { type: Types.Relationship, initial: true, required: true, ref: 'Screening', addNew: false },
  businessUnit: { type: Types.Relationship, initial: true, required: true, ref: 'BusinessUnit', addNew: false }
});

Title.defaultSort = '-createdAt';
Title.defaultColumns = 'name, room';
Title.register();

Would save like this:

title = {
    name: 'name',
    room: 3141234123442,
    businessUnit: {
        name: 'business name',
        _id: 123412341234
    }
}

If no example if someone could just walk me through the best practice on doing a custom relationship field type to store value and id from the relationship select menu I could probably figure it out. This site will have 1000's of documents in each collection so I need to focus on performance and best practices now.

user1572796
  • 1,057
  • 2
  • 21
  • 46
  • Out of the box, the current version of Keystone (0.2.26) does not have a custom field feature. That said, a new fields/component architecture is in the works right now that will allow you to create custom fields, among other things. These new features should be available as of version 0.3.x. – JME Aug 15 '14 at 23:36
  • @JME any date on 0.3? – tgkprog Nov 02 '14 at 13:17
  • 1
    @tgkprog 0.4 is slated for release this month – Harry Moreno Apr 15 '15 at 20:35

1 Answers1

3

You cant make it save like this with Keystone yet but you can make it so that you pass the object as you want to your jade template.

You just need to 'populate' the relationship field as per mongoose / mongodb functionality.

**So your businessUnit model might look like this:

var keystone = require('keystone');
var Types = keystone.Field.Types;

var BusinessUnit = new keystone.List('BusinessUnit', {
    autokey: { from: 'name', path: 'key', unique: true },
    plural: 'BusinessUnits'
});

BusinessUnit.add({
    name: { type: String, required: true },
});   
BusinessUnit.relationship({ ref: 'Title', path: 'title', refPath: 'businessUnit' }); 
BusinessUnit.register();

Your Title model as above

var keystone = require('keystone'),
Types = keystone.Field.Types;

var Title = new keystone.List('Title');

Title.add({
  name: { type: String, required: true, initial: true },
  room: { type: Types.Relationship, initial: true, required: true, ref: 'Screening', addNew: false },
  businessUnit: { type: Types.Relationship, initial: true, required: true, ref: 'BusinessUnit', addNew: false }
});

Title.defaultSort = '-createdAt';
Title.defaultColumns = 'name, room';
Title.register();

The important part of your controller might look like this

//Get all Titles with their nested businessUnits.
view.on('init', function(next) {
  keystone.list('Title').model.find()
  .populate('businessUnit')
  .exec(function(err, results) {
    if(err) {
      console.log(err);
      return next(err);
    } else {
      locals.data.titlesWithNestedBusinessUnits = results;
      next(err);
    }
  });
});

As a side note this will only work one level deep as per the .populate methods capabilities. If you want to go several deep (pretty inefficient) you can use mongoose deep populate . https://github.com/buunguyen/mongoose-deep-populate.