How to validate array which is dynamic in nature Like sometime string and some time objects - joi

I am Using #hapi/joi.
I have an array which store value dynamically, it store string, empty string (an empty array) or an Objects ({"userid": "111jh2jh322j3h2j3h", "msg": 1}).
So it will be like this:
type1-> member: []
type2-> member: ["firstString", "secondString"]
type3-> member: [{"userid": "111jh2jh322j3h2j3h", "msg": 1}, {"userid": "7875jh2jh3545hj3hth", "msg": 0}]
I am confused that how to do validation on #Hapi/joi.
Currently My implementation is:
member: Joi.array().items(Joi.string().allow('')),
I know that If we have an object which is stored under an array then I will do the validation is like:
member: Joi.array().items(Joi.object({
userid: Joi.string(),
msg: Joi.number(),
})),
Any help is really appreciated for that. Thanks in advance.

It will be like this:
member: Joi.array().items(Joi.string().allow(''), Joi.object({
userid: Joi.string(),
msg: Joi.number(),
})),

Related

how to resolve typescript issue with mongodb

I have an issue with this code
const doc = await req.db
.collection('clients')
.find({}, { lName: 1, fName: 1, id: 1 })
giving the typescript error
Type error: Argument of type '{ lName: number; fName: number; id: number; }' is not assignable to parameter of type 'FindOneOptions<any>'.
how can I fix this? thanks!
Solution
This should resolve it for you:
const doc = await req.db
.collection<Client>('clients')
.find({ lName: "", fName: "", id: 1 })
Explaination
The .find() method of Db takes one or two options, where the first option is the FilterQuery and the second is FindOneOptions.
find<T = TSchema>(query?: FilterQuery<TSchema>): Cursor<T>;
find<T = TSchema>(query: FilterQuery<TSchema>, options?: FindOneOptions<T extends TSchema ? TSchema : T>): Cursor<T>;
The options for the second argument are things like sort and limit, not the object to find. What you have in the second argument is the FilterQuery which needs to be the first argument.
The FilterQuery type is generic, so in order for typescript to know that we are filtering clients, we need to pass the generic when calling collection<Client>('clients'). That will cause it to return a collection of Client.
This is the interface I used, but I'm sure there are more properties
interface Client {
lName: string;
fName: string;
id: number;
}
Now, if you pass an invalid type to .find(), typescript knows and will throw and error.
.find({ lName: 1, fName: 1, id: 1 })
This is now an error because I said that fName and lName must be string.
Typescript Playground Link

Unable to insert array data into mongodb using mongoose

I am trying to insert data into my mongodb database. I am using mern stack.
This is my user model for the city data that is in array containing city_name & city_code
city: [{
city_name: {type: String},
city_code: {type: String},
}],
I am passing the values to the register function in this manner
city: [{city_name: this.state.c_name, city_code: this.state.c_code}],
This is the function defined to register into the database
city: [{ city_name: req.body.c_name, city_code: req.body.c_code}],
No error's message is being returned in the console. I am using a message where if the user is registered successfully it returns User Registered or else the error message. But I am not getting anything in the console.
Constructor defined in the front end side to get the values
city: [{city_name: '', city_code: ''}],
UPDATED
This is the function I am using to post the data
export const register = newUser => {
return axios
.post('users/sign-up', {
username: newUser.username,
email: newUser.email,
phone: newUser.phone,
dob: newUser.dob,
city: [{city_name: newUser.c_name, city_code: newUser.c_code}],
password: newUser.password
})
.then(response => {
console.log('Registered')
})
}
SOLUTION
So whenever you are accessing the data stored in array we need to give the index value.
<td>{this.props.obj.city[0].cityname}</td>
<td>{this.props.obj.city[0].citycode}</td>

Initial POST to MongoDB creates an empty object within an array I haven't added anything to

Using the MERN stack I am able to add a document (a Property Schema in this case) via Mongoose. The issue is one of the Property Keys (Rooms in this case) is an Array of Objects. When I initially create the Property I don't send any data regarding the Rooms but a blank Object is created, albeit with a MongoDB _id?
I thought Mongoose prevented creating blank Objects / Arrays if no data was sent or am I confusing matters? Why is it happening? And is there a way to prevent this?
Just to be clear when I initially create the Property I'm sending no information and I don't even reference the rooms array in the data sent from axios.
Here is my Schema:
const propertySchema = new Schema({
propertyId: String,
propertyName: String,
rooms: [
rId: String,
type: String,
class: String,
view: String,
price: String
]
})
Arrays implicitly have a default value of [] (empty array).
But you can prevent it by giving a default: undefined option like this:
const propertySchema = new Schema({
propertyId: String,
propertyName: String,
rooms: {
type: [
new Schema({
rId: String,
type: String,
class: String,
view: String,
price: String,
}),
],
default: undefined,
},
});
Docs (in the Arrays section)
What I realised was I had two controllers, postPropertyController and patchPropertyController. As described in the question when I post the property for the first time I don't include anything in the req.body about the rooms. However, in the postPropertyController I was still doing this...
const propertySchema = new Schema({
propertyId: String,
propertyName: String,
rooms: [
rId: String,
type: String,
class: String,
view: String,
price: String
]
})
What I needed to do to clear the empty object in the rooms array was this...
const propertySchema = new Schema({
propertyId: String,
propertyName: String,
rooms: []
})
Later in the application flow I used a patch method and the patchPropertyController to update the rooms array.
Shout out to #suleymanSah for suggesting something that made me take another look at the code side by side.

Nested maps in mongoose schema

I'm currently creating a fitting mongoose schema for our new JSON format.
It is not very complex but I ran into the issue that certain values are not saved as array but rather as "normalized array" like this:
answers: [{value: 5, string: "abc"}, {value: 4, string: "def"}]
will be:
answers: {
1: {id: 1, value: 5, string: "abc"},
2: {id: 2, value: 4, string: "def"}
}
The Objects themselves can have nested "normalized arrays" as well.
For now I tried using mongoose type "Map" in the top-level-Schema like this:
answers: {
type: Map,
of: answer
}
Where "answer" is a separate mongoose.Schema itself.
But all I get is:
TypeError: Undefined type `Map` at `answers`
Did you try nesting Schemas? You can only nest using refs or arrays.
Why can't I just nest maps as expected? Is it even possible to project this "normalize array" structure in a mongoose schema, and if so, how?
Thank for reading!
I was in the same situation and it seems to work for me:
const ChildSchema = new Schema({
firstName: String,
});
const ParentSchema = new Schema({
name: String,
mapProperty: { type: Map, of: ChildSchema },
});
I do also get the validation triggered from mongoose on the ChildSchema so it seems to accept it just fine.
Hope it helps.

Building a dynamic mongo query for meteor

I'm building an app that has clickable 'filters'; I'm creating a list of objects(?) that I want to pass to a mongo 'find', so that I can pull out listings if selected attributes match a certain score.
My data is structured like this (a snippet):
name: 'Entry One',
location: {
type: 'Point',
coordinates: [-5.654182,50.045414]
},
dogs: {
score: '1',
when: 'seasonal',
desc: 'Dogs allowed from October to April'
},
lifeguard: {
score: '1',
when: 'seasonal',
desc: 'A lifeguard hut is manned between April and October',
times: ''
},
cafe: {
score: '1',
name:'Lovely cafe',
open:'seasonal'
}, ...
My search variable is a list of objects (I think?) that I assign to a session variable. If I output this session var ('searchString') via JSON.stringify, it looks like this:
{"cafe":{"score":"1"},"dogs":{"score":"1"}}
I'd like to pass this to my mongo find so that it only lists entries that match these scores on these attributes, but it's returning zero results. Do I need to somehow make this an $and query?
Currently it looks like this:
Beaches.find(searchString);
Unfortunately as soon as I drop searchString into the find, I get zero results even if it's empty {}. (When it's just a find() the entries list fine, so the data itself is ok)
What am I doing wrong? I'm relatively new to mongo/meteor, so I apologise in advance if it's something stupidly obvious!
Don't stringify the query. Flatten the object instead. Example:
Beaches.find({
"cafe.score": 1,
"dogs.score": 1,
});