How to modify an already constructed schema - meteor

I'm using a third party package that defines a schema like this:
People.schema = new SimpleSchema({
firstName: {
type: String,
optional: false
}
//Many other fields defined...
});
I would like to modify it to have optional: true for the first name without changing the source code for the third party package.
I could use People.schema.pick to get a schema with all of the fields except the firstName, and then combine this with another schema with firstName as optional. But this method would require listing all of the fields in the schema in the pick function, which is tedious.
Is there a better way of accomplishing this?

I can edit the object simple schema creates just like any other object:
People.schema._schema.firstName.optional = true.
To override the field.

Related

Separate form validation with Meteor

I'm using collection2 and I'm trying to get it to handle validation is a specific way. I have a profile schema which looks kind of like this:
Schema.UserProfile = new SimpleSchema({
name: {
type: String,
optional: false
}
location: {
type: String,
optional: true
}
gender: {
type: String,
optional: false
}
});
Schema.User = new SimpleSchema({
username: {
type: String,
optional: true
},
emails: {
type: Array,
optional: true
},
"emails.$": {
type: Object
},
"emails.$.address": {
type: String,
regEx: SimpleSchema.RegEx.Email
},
"emails.$.verified": {
type: Boolean
},
createdAt: {
type: Date
},
profile: {
type: Schema.UserProfile,
optional: true
},
services: {
type: Object,
optional: true,
blackbox: true
},
roles: {
type: [String],
optional: true
},
heartbeat: {
type: Date,
optional: true
}
});
Meteor.users.attachSchema(Schema.User);
Now, on my registration form I'm requiring the user to select their gender and then later once they log in, users are presented with a separate form asking for their name and location. Here's the problem:
The registration form works and everything goes through with saving. When they try to save the internal form with location and name though I get an error:
Error invoking Method 'updateProfile': Gender is required [400]
I know it's happening because it's required in the schema but I've already obtained this information. How do I not require that? Or do I set up validation per form?
You have to add validation through jquery or you can use toaster for display the error on client side.
Read this also : link
I assume you use aldeed:autoform for your forms. When you use normal type in the form, all fields, even those already filled marked as mandatory have to be submitted. Two ways to fix this:
Dirty way: set hidden field with the prefilled value.
You can also set your form type as update as seen in the doc. This way, simple-schema will validate your newDoc already filled with your previous entries without screaming.
The solution number two is the one I use in most cases. This plus autoform's hooks give you enough flexibility to adapt to most use-cases you might encounter.
I don't know whether or not it is a more elegant solution, but we've stopped attaching simpleSchemas to documents in our current project.
We instead have different schemas in each collection's namespace, one for checking user input on insert, one on update, and and one to be used to fill defaultValue when inserting a new doc (which can be done either by the client or the server, in which case we don't check for input). We call .validate() or .clean() depending on what we want to do.
With clever use of the possibility to build schemas from array of schemas, we're not writing bigger schemas in the end (there's more of them though), but we have total control on when we check, and which fields are checked.
From the SimpleSchema docs:
Say you have a required key "friends.address.city" but
"friends.address" is optional. If "friends.address" is set in the
object you're validating, but "friends.address.city" is not, there is
a validation error. However, if "friends.address" is not set, then
there is no validation error for "friends.address.city" because the
object it belongs to is not present.
So the error happens because you're including profile on both forms and gender is not optional within profile. I can think of two ways to solve this:
Have additional objects under profile that are both optional and contain required fields for name/location on one (though it seems like location might be optional in both scenarios based on your code) and a required field for gender on the other. I don't particularly like this solution but it prevents needing form validation.
Use jQuery form validation (I use the package themeteorchef:jquery-validation) and make all your fields in profile optional.
It also looks like SimpleSchema accepts a function for the optional property, so you could use some custom logic there - maybe you get arguments or a context in that function that will allow you to do what you want?
Hope that helps!

Objects with multiple key columns in realm.io

I am writing an app using the Realm.io database that will pull data from another, server database. The server database has some tables whose primary keys are composed of more than one field. Right now I can't find a way to specify a multiple column key in realm, since the primaryKey() function only returns a String optional.
This one works:
//index
override static func primaryKey() ->String?
{
return "login"
}
But what I would need looks like this:
//index
override static func primaryKey() ->[String]?
{
return ["key_column1","key_column2"]
}
I can't find anything on the docs on how to do this.
Supplying multiple properties as the primary key isn't possible in Realm. At the moment, you can only specify one.
Could you potentially use the information in those two columns to create a single unique value that you could use instead?
It's not natively supported but there is a decent workaround. You can add another property that holds the compound key and make that property the primary key.
Check out this conversation on github for more details https://github.com/realm/realm-cocoa/issues/1192
You can do this, conceptually, by using hash method drived from two or more fields.
Let's assume that these two fields 'name' and 'lastname' are used as multiple primary keys. Here is a sample pseudo code:
StudentSchema = {
name: 'student',
primaryKey: 'pk',
properties: {
pk: 'string',
name: 'string',
lastname: 'string',
schoolno: 'int'
}
};
...
...
// Create a hash string drived from related fields. Before creating hash combine the fields in order.
myname="Uranus";
mylastname="SUN";
myschoolno=345;
hash_pk = Hash( Concat(myname, mylastname ) ); /* Hash(myname + mylastname) */
// Create a student object
realm.create('student',{pk:hash_pk,name:myname,lastname:mylastname,schoolno: myschoolno});
If ObjectId is necessary then goto Convert string to ObjectID in MongoDB

Meteor simple-schema: how to get the value of another field that isn't set

I'd like to know the value of another field even when that field hasn't been set in this update, but is part of the document and was set in the past. Is this possible using aldeed:simple-schema?
No. Unless the other field is included in the modifier you have to lookup the document using Collection.findOne and get the field value from that.
Simple you can use for instance:
AutoForm.getFieldValue('profileInformation.dateOfBirth');
age: {
type: String,
optional: true,
defaultValue : function(){
return AutoForm.getFieldValue('profileInformation.dateOfBirth');
}
}

Meteor update a Collection object

in Meteor, I'm having a collection with a Schema, and a number of items are added dynamically.
In this case, I'm dealing with milestones object, and once the user check one off I want to update complete in this Collections item to true (default is false)
Here is my schema
milestones: {
type: Array,
optional: true
},
'milestones.$': {
type: Object
},
'milestones.$.name': {
type: String
},
'milestones.$.hours': {
type: Number
},
'milestones.$.complete': {
type: Boolean
}
How do I write a $set statement for this?
You have an array of objects so, $elemMatch do the trick here.
Projects.update({_id:this._id},{milestones:{$elemMatch:{'milestones.$‌​.name':this.name}},{$set:{'milestone.$.complete':value}}})
So thanks to Aldeed I found a solution - which needs to be called on server side, otherwise it won't let the update happen. Do:
Projects.update({_id:currentPostId, 'milestones.name':name}, {$set:{'milestones.$.complete':true}});
The function is called on the client with Meteor.call with all needed params.
According to your schema you have an object containing an array of objects. So you should write you $set like this:
{$set: {'milestone.$.complete':value}}
This will update the first array element corresponding to the query.
You can find here the official documentation if you want to know more about arrays updates in Mongo.

Is there a way to handle inheritance using SimpleSchema?

I have a basic collection called Tasks. I want to create a new Collection called DailyTasks, where a DailyTask extends a Task, and also has a list of Dates on which the DailyTask was completed.
I want Tasks.findAll() to return Tasks and DailyTasks.
I would be willing to have three classes: BaseTask, OneTimeTask (which has a single dateCompleted field) and DailyTask (which has a list of datesCompleted). I would need to know how to configure my schema accordingly.
How can I do this?
You can pass multiple schemas to the SimpleSchema constructor, and they will be combined. Like so:
Tasks = new SimpleSchema({ ... });
DailyTasks = new SimpleSchema([Tasks, {
additionalField: {
type: String
}
}]);

Resources