In my Yup schema I was my String field name to allow you to pass in any string, an empty string, or nothing at all. If you pass in a string, it passes. If you pass in an empty string or nothing, I want to convert to a default value.
This is the schema that I thought would cover it:
const mySchema = yup.object().shape({
name: yup.string('Name must be a string').max(100, 'Name has a max of 100 characters').default('John Doe')
});
However, if I pass in an empty string '', it does not trigger the default conversion and it just passed through as an empty string. I've tried adding required() but that just makes the line fail if I pass an empty string. I've tried nullable() and trim() but nothing seems to work.
How can I make the default value replace empty strings?
I ended up adding a simple method to transform empty string to undefined which will get picked up in the default:
// Add method
yup.addMethod(yup.string, 'stripEmptyString', function () {
return this.transform((value) => (value === '' ? undefined : value));
});
// Usage
const mySchema = yup.object().shape({
name: yup.string('Name must be a string').stripEmptyString().default('John Doe')
});
Related
This is how I'm currently trying to write an array of strings to a opcua variable on a opcua server ( attached image 2 gives attributes ). The method below takes in a string[] and tries to write this string to the variable. I can read the variable easily, with a similar method.
async writeFeatureName(arrayToWrite: String[]): Promise <any> {
console.log(arrayToWrite);
let nodesToWrite = [{
nodeId: "ns=3;s=\"DB_ScvsInterface01".\"OUT\".\"FeatureName\"",
attributeId: AttributeIds.Value,
value: new DataValue({
statusCode: StatusCodes.Good,
value: new Variant({
dataType: DataType.String,
arrayType: VariantArrayType.Array,
value: arrayToWrite
})
}),
}];
const dataValue = await this.session.write(nodesToWrite);
winston.debug(`wrote Feature Name Array : ${dataValue.toString()}`);
return dataValue
}
When I try to write to the variable on the server, I get a type mismatch. The array is of type string[]. I've tried various recommendations, but I do not find a clear example of writing an array to an array on the server? Is this even possible ?
this image shows the error i'm getting, which is a type mismatch
this is the server attributes for the variable I'm trying to write to
You are using the correct technic to write an array of string to the variable.
However, the arrayDimension attribute of the variable is [60], which specifies that the variable should contain 60 element in the array.
I wonder if the arrayToWrite contains 60 elements , Can you check ?
I am trying to use the "or" operator in Joi ver.17.4.0
As you can see, in the code below, I want either or both of the attributes/properties to be allowed, but not neither.
The problem is that Joi does not allow a string to be empty. So, to have it empty, I need to:
Joi.string().allow('')
This makes it not empty according to the "or" operator. So I can not get the 'name' to be empty in the eyes of "or".
It won't validate properly.
It validates even when I do this (but it shouldn't):
validatePerson(createPerson(''));
Keep in mind that I'm actually validating POST input on a node express API, so this is some simplified code to illustrate the issue:
const Joi = require('Joi');
function createPerson(name, age) {
const person = { name: name, age: age };
console.log(person);
return person;
}
function validatePerson(person) {
const schema = Joi.object({
name: Joi.string().allow(''),
age: Joi.number(),
}).or("name", "age");
console.log(schema.validate(person));
return schema.validate(person);
}
validatePerson(createPerson('')); // This should fail validation but doesn't
validatePerson(createPerson()); // Should fail and does
validatePerson(createPerson('Bob')); // Should pass and does
validatePerson(createPerson('', 7)); // Should pass and does
validatePerson(createPerson('Bob', 7)); // Should pass and does
As far as I understand, you want to allow the name to be empty an string, only if the age exists.
To acheive that, you can use .when:
name: Joi.string().when('age', { is: Joi.exist(), then: Joi.allow('') })
This way, your first example will fail as you expected.
I have a mongoose schema where I'm storing a port number. I also have a default value set for the field.
port:{
type:Number,
default:1234
}
If I don't get any value via my API, it gets set to 1234.
However, If someone sends null, it accepts null and saves to database.
Shouldn't it covert null to 1234? null is not a number! Am I understanding it wrong?
I am considering the solution given here, but I dont want to add extra code for something that should work without it (unless I'm wrong and its not supposed to convert null to 1234)
See the comments in this issue:
https://github.com/Automattic/mongoose/issues/2438
null is a valid value for a Date property, unless you specify required. Defaults only get set if the value is undefined, not if its falsy.
(it's about dates but it can be applied to numbers just as well.)
Your options are to either:
add required to the field
add a custom validator that would reject it
use hooks/middleware to fix the issue
You might get away with a pre-save or post-validate (or some other) hook like this:
YourCollection.pre('save', function (next) {
if (this.port === null) {
this.port = undefined;
}
next();
});
but probably you'll have to use something like:
YourCollection.pre('save', function (next) {
if (this.port === null) {
this.port = 1234; // get it from the schema object instead of hardcoding
}
next();
});
See also this answer for some tricks on how to make null trigger default values in function invocation:
Passing in NULL as a parameter in ES6 does not use the default parameter when one is provided
This is unfortunate that Mongoose cannot be configured to tread null as undefined (with some "not-null" parameter or something like that) because it is sometimes the case that you work with data that you got in a request as JSON and it can sometimes convert undefined to null:
> JSON.parse(JSON.stringify([ undefined ]));
[ null ]
or even add null values where there was no (explicit) undefined:
> JSON.parse(JSON.stringify([ 1,,2 ]));
[ 1, null, 2 ]
As explained in mongoose official docs here
Number
To declare a path as a number, you may use either the Number global constructor or the string 'Number'.
const schema1 = new Schema({ age: Number }); // age will be cast to a Number
const schema2 = new Schema({ age: 'Number' }); // Equivalent
const Car = mongoose.model('Car', schema2);
There are several types of values that will be successfully cast to a Number.
new Car({ age: '15' }).age; // 15 as a Number
new Car({ age: true }).age; // 1 as a Number
new Car({ age: false }).age; // 0 as a Number
new Car({ age: { valueOf: () => 83 } }).age; // 83 as a Number
If you pass an object with a valueOf() function that returns a Number, Mongoose will call it and assign the returned value to the path.
The values null and undefined are not cast.
NaN, strings that cast to NaN, arrays, and objects that don't have a valueOf() function will all result in a CastError.
In my documents pre save hook, I check if all the properties from the nested property accident exist and have correct values. If accident does not exist at all this is also fine.
When I'm trying to save a doc which has no value on the nested property accident of my doc it still goes into my custom validation rules. This is because I fail to detect if this nested object is empty.
Property in the Schema
prescriptionSchema = mongoose.Schema({
accident: {
kind: String, #accident, workAccident,
date: Date,
company: String
},
...
Pre Save Hook
console.log _.isEqual(data.accident, {}) #false
console.log JSON.stringify data.accident #{}
console.log JSON.stringify data.accident == JSON.stringify {} #false
console.log JSON.stringify {} #{}
console.log Object.keys(data.accident).length #14
for key, value of data.accident
console.log key, value #gives me basically the whole document with functions etc.
Current Detection (not good code)
if data.accident? && (data.accident['kind'] || data.accident['date'] || data.accident['company']) #=> do validation
Seed
newRecipe = new RecipeModel()
for key, value of recipe
newRecipe[key] = value
newRecipe.save((err, result) ->
return next err if err?
return next "No Id" if !result._id?
return next null, result._id
)
I tried {}, null and nothing as values for recipe.accident.
Mongoose Version: 4.0.2
Node Version: 5.9
This solution worked although I now have _ids on the embedded objects which I don't need.
I moved out the object from the main schema and defined it as a own sub schema:
drugSchema = mongoose.Schema({
name: String,
exchangeable: Boolean
})
accidentSchema = mongoose.Schema({
kind: String, #accident, workAccident,
date: Date,
company: String
})
prescriptionSchema = mongoose.Schema({
drugs: [drugSchema],
dutiable: Boolean,
accident: accidentSchema,
...
After this, the object is undefined in the pre save hook.
By default, mongoose won't save empty objects. You need to disable the minimize option in your Schema.
prescriptionSchema = mongoose.Schema({
accident: {
kind: String, #accident, workAccident,
date: Date,
company: String
},
...
}, {
minimize: false
})
Source : http://mongoosejs.com/docs/guide.html#minimize
UPDATE : If it is not saving the object, you can try to use the markModified() method (http://mongoosejs.com/docs/schematypes.html#mixed).
And for your checking problem, you can perform a function which will check your fields. Here's two examples : https://jsfiddle.net/ew2um2dh/13/
I am writing expressjs app. is req.params.anything always string and not number
suppose if I pass a number for user_id it's typeof is always string.
app.get('user/:user_id', function(req, res){
console.log(typeof req.params.user_id);
});
GET user/21
this logs string.
So is it always type string for req.params.x?
Yes, all params will be strings.
This is extracted from the expressjs route.js:
var val = 'string' == typeof m[i]
? decodeURIComponent(m[i])
: m[i];
So the val will always be a string, since the result of decodeURIComponent is always a string, while m is the result of a RegExp.exec() which returns an array of matched strings, so it's also safe to assume that m[i] will be a string.