SimpleSchema: How to get ``pick`` working with SubSchemas? (solved)

Hi guys,

I stumbled upon an issue when using pick with SimpleSchema.

Does anyone know how to get this working? (I indicated where the problem is in the code)

@aldeed: Any ideas? :smile:

SubSchema = new SimpleSchema({
  name: {
    type: String,
  },
});

MainSchema = new SimpleSchema({
  // ..
  subschema: {
    type: SubSchema,
  },
  // ..
});

// BUG BUG BUG
// Pick does NOT work as excpected
// .. this only returns a FLAT object, with NO "name"-field attached
AnotherSchema = MainSchema.pick(['subschema']);  
// Note: .pick(['subschema', 'subschema.$']); does NOT help

Any ideas?

How about something like this?

MainSchema = new SimpleSchema([
  SubSchema,
  {
    mainField: {type: String}
  }
])

Thanks for your feedback… unfortunatly this is not what I want to achieve as it embedds SubSchema’s fields into the root of MainSchema (for example like PickedSchema.name).
I actually need to embedd SubSchema’s fields into an extra dedicated field called ‘subschema’, like PickedSchema.subschema.name.

… something like this would work (but is not what I need to have as illustrated above).

SubSchema = new SimpleSchema({
  name: {
    type: String,
  },
});

MainSchema = new SimpleSchema([
  SubSchema, // this embedds SubSchema's fields into the root of MainSchema
             // p.e. like ``MainSchema.name``
             // 
             // BUT I need to have it in an extra field,
             // p.e. like ``MainSchema.subschema.name``
]);

PickedSchmema = MainSchema.pick(['name']);  

Ok, I think I got the solution…

SubSchemaDefinition = {
  name: {
    type: String,
    custom: function() {
      return 'custom return';
    }
  },
  dates: {
    type: [Object],
    optional: true,
    custom: function() {
      return 'custom return';
    }
  },
};
SubSchema = new SimpleSchema(SubSchemaDefinition);

MainSchemaDefinition = {
  subschema: {
    type: SubSchema,
    optional: false,
    // .. other configuration, like validation, autoValue, etc.
  },
};
MainSchema = new SimpleSchema(MainSchemaDefinition);
MainSchema.messages({
  'buggyError': 'Custom error message',
});

PickedSchmema = MainSchema.pick(
  ['subschema', 
  'subschema.name',
  'subschema.dates',
  'subschema.dates.$']
);
PickedSchmema.messages(MainSchema._messages);  // messages are NOT picked and need to be transported

@aldeed: Is there any trick to this WITHOUT having to manually indicating all the sub-schema-fields?
This here kind of sucks

PickedSchmema = MainSchema.pick(
  ['subschema', 
  'subschema.name',
  'subschema.dates',
  'subschema.dates.$']
);

OKOKOK…

here is my final solution, which automatically picks fieldnames in order to keep it DRY:

/**
 * Helper to pick fieldNames for a SubSchema from an SimpleSchema.
 * @param  {SimpleSchema} schema
 * @param  {String} subSchemaFieldName Field-Name of the subschema, p.e. ``subschema1``
 * @return {Array} Array of fieldnames that belong to the SubSchema
 */
function pickKeysForSubSchema(schema, subSchemaFieldName) {
  var returnArray = [];
  for (fieldName of schema._schemaKeys) {
    var searchPatternForArrayFields = subSchemaFieldName + '.';
    if (fieldName===subSchemaFieldName 
      || s.startsWith(fieldName, searchPatternForArrayFields) // underscorestring:underscore.string
      ) {
      returnArray.push(fieldName);
    }
  }
  return returnArray;
}

SubSchema1 = new SimpleSchema({
  name: {
    type: String,
    custom: function() {
      return 'custom return';
    }
  },
  dates: {
    type: [Object],
    optional: true,
    custom: function() {
      return 'custom return';
    }
  },
});
SubSchema2 = new SimpleSchema({
  hobby: {
    type: String,
    custom: function() {
      return 'custom return';
    }
  },
  places: {
    type: [Object],
    optional: true,
    custom: function() {
      return 'custom return';
    }
  },
});

MainSchema = new SimpleSchema({
  subschema1: {
    type: SubSchema1,
    optional: false,
    // .. other configuration, like validation, autoValue, etc.
  },
  subschema2: {
    type: SubSchema2,
    optional: false,
    // .. other configuration, like validation, autoValue, etc.
  },
});
MainSchema.messages({
  'buggyError': 'Custom error message',
});

// this works, but is too much manual work and not really DRY
// PickedSchema = MainSchema.pick(
//   ['subschema', 
//   'subschema.name',
//   'subschema.dates',
//   'subschema.dates.$']
// );
PickedSchema = MainSchema.pick(pickKeysForSubSchema(MainSchema, 'subschema1'));
PickedSchema.messages(MainSchema._messages);  // messages are NOT picked and need to be transported

This is something I’ve already fixed in simple-schema v2 (work in progress), but because it would not be backwards compatible to change it, I’m not fixing in v1.

1 Like