This is my simplified collection & its schema:
Comments = new Mongo.Collection('comments');
Comments.schema = new SimpleSchema({
attachments: {type: [Object], optional: true},
});
Comments.attachSchema(Comments.schema);
And this is my simplified method:
Meteor.methods({
postComment() {
Comments.insert({
attachments: [{type:'image', value:'a'}, {type: 'image', value:'b'}]
});
}
});
After invoking the method, this is the document I've got in MongoDB:
{
"_id" : "768SmgaKeoi5KfyPy",
"attachments" : [
{},
{}
]
}
The objects in the array don't have any properties!
Now if I comment this line out:
Comments.attachSchema(Comments.schema);
and call the method again, the inserted document now seems correct:
{
"_id" : "FXHzTGtkPDYtREDG2",
"attachments" : [
{
"type" : "image",
"value" : "a"
},
{
"type" : "image",
"value" : "b"
}
]
}
I must be missing something fundamental here. Please enlighten me.
I'm using the latest version of Meteor (1.2.1).
From the simple-schema docs:
If you have a key with type Object, the properties of the object will be validated as well, so you must define all allowed properties in the schema. If this is not possible or you don't care to validate the object's properties, use the blackbox: true option to skip validation for everything within the object.
So you'll want to add blackbox:true to your attachments' options.
Comments.schema = new SimpleSchema({
attachments: {type: [Object], optional: true, blackbox: true},
});
Related
I'm trying to insert an array into an object and I'm not having any luck. I think the schema is rejecting it based on validation but I'm not sure why. If I console.log(this.state.typeOfWork) and check typeof it states its an Object which contains:
(2) ["Audit - internal", "Audit - external"]
0: "Audit - internal"
1: "Audit - external"
My collection after an update contains:
"roleAndSkills": {
"typeOfWork": []
}
Example: Schema
roleAndSkills: { type: Object, optional: true },
'roleAndSkills.typeOfWork': { type: Array, optional: true },
'roleAndSkills.typeOfWork.$': { type: String, optional: true }
Example: update
ProfileCandidate.update(this.state.profileCandidateCollectionId, {
$set: {
roleAndSkills: {
typeOfWork: [this.state.typeOfWork]
}
}
});
Simple schema has some problems with validation on Objects or Arrays, i had the same problem in a recent app i developed.
What can you do?
well, what i did, on the Collections.js file, when you are saying:
typeOfWork:{
type: Array
}
Try adding the property blackbox:true, like this:
typeOfWork:{
blackbox: true,
type: Array
}
This will tell your Schema that this field is taking an Array, but ignore further validation.
The validation i made was on main.js, just to be sure i had no empty array and the data was plain text.
As requested here is my update method, im my case i used objects not arrays but it works the same way.
editUser: function (editedUserVars, uid) {
console.log(uid);
return Utilizadores.update(
{_id: uid},
{$set:{
username: editedUserVars.username,
usernim: editedUserVars.usernim,
userrank: {short: editedUserVars.userrank.short,
long: editedUserVars.userrank.long},
userspec: {short: editedUserVars.userspec.short,
long: editedUserVars.userspec.long},
usertype: editedUserVars.usertype}},
{upsert: true})
},
here it the collection schema
UtilizadoresSchema = new SimpleSchema({
username:{
type: String
},
usernim:{
type: String
},
userrank:{
blackbox: true,
type: Object
},
userspec:{
blackbox: true,
type: Object
},
usertype:{
type: String
}
});
Utilizadores.attachSchema(UtilizadoresSchema);
Hope it helps
Rob
typeOfWork is an Array. You should push your value in it :
$push: {
"roleAndSkills.typeOfWork": this.state.typeOfWork
}
for multiple values :
$push: {
"roleAndSkills.typeOfWork": { $each: [ "val1", "val2" ] }
}
mongo $push operator
mongo dot notation
You state that this.state.typeOfWork is an array (of strings) but then when you .update() your document you are enclosing it in square brackets:
ProfileCandidate.update(this.state.profileCandidateCollectionId, {
$set: {
roleAndSkills: {
typeOfWork: [this.state.typeOfWork]
}
}
});
Simply remove the redundant square brackets:
ProfileCandidate.update(this.state.profileCandidateCollectionId, {
$set: {
roleAndSkills: {
typeOfWork: this.state.typeOfWork
}
}
});
Also since your array is just an array of strings you can simplify your schema a bit by declaring it as such with [String] for the type:
'roleAndSkills.typeOfWork': { type: [String] }
Note furthermore that objects and arrays are by default optional so you can even omit the optional flag.
I am trying to build a kind of specific simple schema for a collection and i would like to make sure that :
when the user enter a new select in my selectsCollection, he will put one of the options value as selected value.
For example:
SelectsCollection.insert({name:"SelectOne",deviceType:"Select",options:["option1","option2","option3"],value:"option4",description:"This is the first select"});
this do not have to work. I want him to write only one of the 3 options.
Here my schema :
SelectsCollection = new Mongo.Collection('Selects'); //Create a table
SelectsSchema = new SimpleSchema({
name:{
type: String,
label:"Name",
unique:true
},
deviceType:{
type: String,
allowedValues: ['Select'],
label:"Type of Device"
},
options:{
type: [String],
minCount:2,
maxcount:5,
label:"Select Values"
},
value:{
type: String,
//allowedValues:[options] a kind of syntax
// or allowedValues:function(){ // some instructions to retrieve the array of string of the option field ?}
label:"Selected Value"
},
description:{
type: String,
label:"Description"
},
createdAt:{
type: Date,
label:"Created At",
autoValue: function(){
return new Date()
}
}
});
SelectsCollection.attachSchema(SelectsSchema);
Any Idea ? :)
Thanks a lot !
This could be done with custom validation function of a field, inside this function you could retrieve values from other fields:
SelectsSchema = new SimpleSchema({
// ...
options: {
type: [String],
minCount: 2,
maxcount: 5,
label: "Select Values"
},
value: {
label: "Selected Value",
type: String,
optional: true,
custom() {
const options = this.field('options').value
const value = this.value
if (!value) {
return 'required'
}
if (options.indexOf(value) === -1) {
return 'notAllowed'
}
}
},
// ...
});
Look here custom-field-validation for more information
I am trying to save variant options as an object, something like that:
{'1' : {optionTitle: 'title', optionPrice: 12}, '2': {....}}
//schema
RestMenuVariants.attachSchema(new SimpleSchema({
restRefId: {type: String},
createdBy:{type: String},
title: {type: String},
options: {type: Object},
sortId: {type: String, optional: true},
createdAt: {type: Date}
}));
//part of the method addMenuVariantItem
return RestMenuVariants.insert({
restRefId: restId,
createdBy: Meteor.userId(),
createdAt: new Date(),
title: title,
options: options,
sort_id: sortId
});
// part of the event for loop which creates the object
variantOptions[i] = {optionTitle: $(element).val(), optionPrice: $(elementPrice).val()};
}
// and calling the method
Meteor.call('addMenuVariantItem', this._id, this.createdBy, variantTitle, variantOptions, function(error, result){.....})
I don't get any check or other errors, the variant is saved but when I look for the item at the console i see that the options is an empty object:
//var cursor = RestMenuVariants.findOne({_id: id});
//console.log(cursor.options)
Object {}
What am I missing?
Thanks.
It looks like variantOptions is being created as an array but your schema only expects an object.
Change:
options: {type: Object}
to
options: {type: [Object], blackbox: true },
in your schema definition.
The blackbox: true option tells simple-schema to ignore the structure of the objects being put into the options array.
Also note that an array is != a nested object with numbered keys as you have in your description. You won't get:
{
'1': {optionTitle: 'title', optionPrice: 12},
'2': {....}
}
Instead you'll see:
[
{ optionTitle: 'title', optionPrice: 12 },
{....}
]
In my Meteor app, I have a simple array field called relatedSentences. It is defined using SimpleSchema
relatedSentences: {
type: [String],
label: "Related Sentence",
optional: false,
defaultValue: []
},
It's data can be seen in the Mongo console:
"_id" : "ei96FFfFdmhPXxRWb",
"sentence" : "the newest one",
"relatedSentences" : [
"Ls6EyBkbcotcyfLyw",
"6HKQroCjZhG9YCuBt"
],
"createdAt" : ISODate("2015-10-25T11:21:25.338Z"),
"updatedAt" : ISODate("2015-10-25T11:41:39.691Z")
But when I try to access this field using this, it is returned as a raw string.
Template.showSentence.helpers({
translations: function() {
console.log("related: " + this.relatedSentences);
Meteor.subscribe('sentences', function() {
var relatedSentences = Sentences.find({_id: {$in: this.relatedSentences} }).fetch();
console.log("rel count" + relatedSentences.length);
return relatedSentences;
});
}
});
In the console I get an error. See the return value from the this.relatedSentences. It is the contents of the array as a string, with a comma interpolated.
related: Ls6EyBkbcotcyfLyw,6HKQroCjZhG9YCuBt
selector.js:595 Uncaught Error: $in needs an array
Not sure what is going on here.
Some Progress
I have made some progress, but not yet at a solution. By adding blackbox: true to the SimpleSchema definition, what looks like an array is now returned... but alas it is still failing. See below.
relatedSentences: {
type: [String],
label: "Related Sentence",
optional: false,
blackbox: true,
defaultValue: []
},
Now I get the results below in the console. The values are now being returned as a quoted array, which is what I expected. But the $in is still not seeing it as an array.
["Ls6EyBkbcotcyfLyw", "6HKQroCjZhG9YCuBt"]
selector.js:595 Uncaught Error: $in needs an array
How did the data get populated
In answer to #Kyll - this is how the data was originally populated. I am using AutoForm,
{{> afQuickField name='relatedSentences.0' value=this._id type="hidden"}}
but then adding the array data via a hook.
AutoForm.addHooks('translateForm', {
onSuccess: function (operation, result, template) {
Meteor.subscribe('sentences', function() {
var translatedSentence = Sentences.findOne(result);
var originalSentenceId = translatedSentence.relatedSentences[0]
Sentences.update(
{ _id: originalSentenceId},
{ $push: { relatedSentences: result}
});
Router.go('showSentence',{ _id: originalSentenceId } );
});
}
});
The problem here is the scope of this. You are referring to it inside the subscribe function, where this has a different context. Set a varibale to this in the context where it works, then use that variable instead:
Template.showSentence.helpers({
translations: function() {
console.log("related: " + this.relatedSentences);
var this_related_sentences = this.relatedSentences;
Meteor.subscribe('sentences', function() {
var relatedSentences = Sentences.find({_id: {$in: this_related_sentences} }).fetch();
console.log("rel count" + relatedSentences.length);
return relatedSentences;
});
}
});
Let's say, we have this schema :
Schemas.MyCollection = new SimpleSchema({
something: {
type: Object
}
});
I want to insert something into MyCollection. For example :
var myobj = {
aaaaaa: 11111,
bbbbbb: 22222
};
MyCollection.insert({something: myobj});
We end up with this :
{
_id: "someId",
something: {}
}
When I disable simple schema checking (collection2), everything works as one expected.
Simple-schema did not report an error (collection2) so why it is invalid?
#Seraph your schema is wrong
Schemas.MyCollection = new SimpleSchema({
something: {
type: Object
},
'something.aaaaa': {
type: String
}
});
and so on you have to write every property the object has or you can do blackbox: true if you don't want to validate the object:
something: {
type: Object,
blackbox: true
}
Also if it's server-side operation you can do myCollection.insert(doc, {validate: false});
just read the docs https://atmospherejs.com/aldeed/collection2 :)
Here is the reference to help you understand more:
https://github.com/aldeed/meteor-simple-schema#blackbox