Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding an item name to a relationship field in keystone.js

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.

like image 753
user1572796 Avatar asked Oct 21 '22 03:10

user1572796


1 Answers

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.

like image 177
Jeremy Hindle Avatar answered Oct 29 '22 17:10

Jeremy Hindle