Joi - not.exist()? - javascript

I am trying to do a validation with Joi, but I came to a scenario that I cannot achieve. I have an object. In some cases, the object will have an id (edit) and on the others it will not (create).
I want to validate that in case "id" is not present, few other fields should be there.
So far my only solution that works is when id is null and not missing at all. Is there a way to match non-existing key or should I change it to null (a bit hacky).
joi.object().keys({
id: joi
.number()
.min(0)
.allow(null),
someOtherField1: joi.when("id", { is: null, then: joi.required() })
});
Thank you in advance!

Undefined is the empty value for Joi. Use "not" instead of "is"
Example: { not: Joi.exist(), then: Joi.required() }

If you're prepared to accept null as an id and would like to perform conditionals on it I'd suggest defaulting the id field to null. This way you can omit it from the payload and still query it using Joi.when().
For example:
Joi.object().keys({
id: Joi.number().min(0).allow(null).default(null),
someOtherField1: Joi.string().when('id', { is: null, then: Joi.required() })
});
Passing both an empty object, {}, and an object with a null id, { "id": null }, will result in:
ValidationError: child "someOtherField1" fails because ["someOtherField1" is required]

Related

In DymanoDB/Dynamoose, how can I set a schema of a map of string keys and number values?

So I have this instructions:
Schema Defs:
Result object:
It's a map of string keys and number values
"result": { "M": { [STRING]: { "N": "401" } },
This is what I have so far
result: {
type: Object,
schema: {
// I am getting 2 errors:
// Parsing error: Unexpected token, expected "]"
// ',' expected.
[id: String]: Number
},
required: true
},
Any ideas?
[id: String] is a TypeScript thing. Not allowed in standard JavaScript.
This is not technically possible in Dynamoose. The only option here is to use the saveUnknown schema setting.
This was brought up in a conversation before, and the user who wanted to do this I told to create an issue on the GitHub repo but it doesn't look like that happened. If you'd like support for this in Dynamoose in the future, please submit a feature request on the GitHub repo.
Edit
In order to do this your schema would looks something like:
new dynamoose.Schema({
result: {
type: Object,
required: true
},
}, {
"saveUnknown": ["result.**"]
});
This will allow indefinitely nested objects within result.

Edit readonly javascript objects

I have a read-only object that is returned by GraphQL (vue-apollo) query, the result which is read-only looks something like this:
result: {
id: 'yh383hjjf',
regulations: [{ title: 'Test', approved: false}]
})
I want to bind this to a form and be able to edit/update the values in the regulations array and save it back to the database.
at the moment when I try to edit I get the error below:
Uncaught TypeError: "title" is read-only
I tried cloning the result returned by the database using object.assign
//target template
const regulatoryApprovals = {
id: null,
regulations: [{ title: null, approved: null}]
})
regulatoryApprovals = Object.assign(regulatoryApprovals, result, {
regulations: Object.assign(regulatoryApprovals.regulations, result.regulations)
})
but this didn't work.
Does anyone know how I can properly clone the result?
regulatoryApprovals= Object.assign(regulatoryApprovals, ... indicates the problem because regulatoryApprovals is modified with Object.assign, so it would need no assignment.
Read-only regulatoryApprovals object needs to be cloned. regulations is an array and won't be merged correctly with Object.assign, unless it's known that array elements need to be replaced. It should be:
regulatoryApprovals = {
...regulatoryApprovals,
...result,
regulations: [...regulatoryApprovals.regulations, result.regulations]
}
Where { ...regulatoryApprovals, ... } is a shortcut for Object.assign({}, regulatoryApprovals, ...).

Mongoose: value not incrementing through $inc

I have been struggling with this issue for days. For some unknown reason, a specific field ("reviewCounts") is not incrementing no matter what alternative methods I try.
Here is my Schema
let itemSchema = new mongoose.Schema({
rank: Number,
image: String,
name: String,
title: String,
count: Number,
category: String,
ratings: Object,
reviewCounts: Number,
reviews: Array,
tags: Object,
})
and this is the update method:
Item.findOneAndUpdate({name: item,title:title}, {
$inc:{"reviewCounts":1},
$set:averageQuery,
$inc:query
},{strict:false},
function (err, data) {
}
}
$inc works completely find on "query" not it does not increment "reviewCounts". I have tried using $set to manually set the value, but that did not work too. I doubled-checked and confirmed that the field is int32 as intended. What could be the reason behind this issue?
When you build your update statement this way:
{
$inc:{"reviewCounts":1},
$set:averageQuery,
$inc:query
}
you're duplicating the $inc key in your JavaScript object. JavaScript interprets such code as:
{
$set:averageQuery,
$inc:query
}
so simply last usage of particular key "wins" thus you loose the reviewCounts part.
You need to make sure that there's only one $inc and you can use the spread operator to combine your $inc's:
$inc:{ ...query, "reviewCounts":1 }

DynamoDB putItem ConditionExpression "boolean" true

am trying to do a ConditionExpression in a DynamoDB put to check whether a stored boolean is true (in this example, whether the user is already verified don't run the put), i'm using the javascript DocumentClient SDK (thanks to #shimon-tolts), the code looks like:
var query = {
TableName: tableName,
Item: {
email: email,
verified: false,
verifyToken: token
},
ConditionExpression: 'attribute_exists(email) AND verified = :bool',
ExpressionAttributeValues: {
":bool":"false"
}
};
dynamodb.put(query, function(err, data){
if (err) return fn(err)
fn(null, data);
});
Which doesn't work, it fails the condition check no matter what the call.
Pretty much what I need (in pseudocode):
IF email already exists AND verified equals false
THEN allow PUT
IF email already exists AND verified equals true
THEN don't allow PUT
IF email does not exist
THEN allow PUT
Any ideas?
I suggest using DocumentClient as it works with javascript objects.
To do a condition expression you have to specify the ExpressionAttributeNames and ExpressionAttributeValues for example::
ConditionExpression: "#yr <> :yyyy and title <> :t",
ExpressionAttributeNames:{"#yr":"year"},
ExpressionAttributeValues:{
":yyyy":year,
":t":title
}
You can see more examples here and read more here
I finally got this to work after figuring out the right ExpressionAttributeValues:
dclient.scan(TableName='bix-workflow-images',
FilterExpression="wgs = :t or attribute_not_exists(wgs)",
ExpressionAttributeValues={':t':{'BOOL':True}})
I am stumbling about this because I have a similar problem and although this is a year old, for me it looks like your boolean shouldn't be a string:
ExpressionAttributeValues: {
":bool": "false"
}
Instead:
ExpressionAttributeValues: {
":bool": false
}
Have you tried it that way?

Cannot infer query fields to set error on insert

I'm trying to achieve a "getOrCreate" behavior using "findAndModify".
I'm working in nodejs using the native driver.
I have:
var matches = db.collection("matches");
matches.findAndModify({
//query
users: {
$all: [ userA_id, userB_id ]
},
lang: lang,
category_id: category_id
},
[[ "_id", "asc"]], //order
{
$setOnInsert: {
users: [userA_id, userB_id],
category_id: category_id,
lang: lang,
status: 0
}
},
{
new:true,
upsert:true
}, function(err, doc){
//Do something with doc
});
What i was trying to do is:
"Find specific match with specified users, lang and category... if not found, insert a new one with specified data"
Mongo is throwing this error:
Error getting/creating match { [MongoError: exception: cannot infer query fields to set, path 'users' is matched twice]
name: 'MongoError',
message: 'exception: cannot infer query fields to set, path \'users\' is matched twice',
errmsg: 'exception: cannot infer query fields to set, path \'users\' is matched twice',
code: 54,
ok: 0 }
Is there a way to make it work?
It's impossible?
Thank you :)
It's not the "prettiest" way to handle this, but current restrictions on the selection operators mean you would need to use a JavaScript expression with $where.
Substituting your vars for values for ease of example:
matches.findAndModify(
{
"$where": function() {
var match = [1,2];
return this.users.filter(function(el) {
return match.indexOf(el) != -1;
}).length >= 2;
},
"lang": "en",
"category_id": 1
},
[],
{
"$setOnInsert": {
"users": [1,2],
"lang": "en",
"category_id": 1
}
},
{
"new": true,
"upsert": true
},
function(err,doc) {
// do something useful here
}
);
As you might suspect, the "culprit" here is the positional $ operator, even though your operation does not make use of it.
And the problem specifically is because of $all which is looking for the possible match at "two" positions in the array. In the event that a "positional" operator was required, the engine cannot work out ( presently ) which position to present. The position should arguably be the "first" match being consistent with other operations, but it is not currently working like that.
Replacing the logic with a JavaScript expression circumvents this as the JavaScript logic cannot return a matched position anyway. That makes the expression valid, and you can then either "create" and array with the two elements in a new document or retrieve the document that contains "both" those elements as well as the other query conditions.
P.S Little bit worried about your "sort" here. You may have added it because it is "mandatory" to the method, however if you do possibly expect this to match "more than one" document and need "sort" to work out which one to get then your logic is slightly flawed.
When doing this to "find or create" then you really need to specifiy "all" of the "unique" key constraints in your query. If you don't then you are likely to run into duplicate key errors down the track.
Sort can in fact be an empty array if you do not actually need to "pick" a result from many.
Just something to keep in mind.

Categories