I think the redundancy here can be removed by using some function insde ramda but I am very new to this library so i cant think of how.Some help would be really appreciated
let lib = {
getFormattedPropsForUser: R.compose(
R.pickBy(R.identity),
R.applySpec({
username: R.prop('username'),
password: R.prop('password')
})),
getFormattedQueryParamsForUser: R.compose(
R.pickBy(R.identity),
R.applySpec({
_id: R.prop('_id'),
username: R.prop('username'),
password: R.prop('password')
})
)
};
Extract the common part of both applications to a function, and add the ability to add more items to the spec using partial application and object spread.
Example:
const forUser = spec => R.compose(
R.pickBy(R.identity),
R.applySpec({
...spec,
username: R.prop('username'),
password: R.prop('password')
})
)
const lib = {
getFormattedPropsForUser: forUser(),
getFormattedQueryParamsForUser: forUser({ _id: R.prop('_id') }),
}
const test = { _id: 'id', username: 'username', password: 'password' }
console.log(lib.getFormattedPropsForUser(test))
console.log(lib.getFormattedQueryParamsForUser(test))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
I think you can simplify your functions quite a bit, and abstract the common parts out relatively easily. Here getActualProps does much the same as your applySpec/pickBy(identity) shuffle, with the actual fields parameterized. Then the two functions (or library methods) can be written in terms of it.
const getActualProps = (names) => pickBy((v, k) => includes(k, names))
const getFormattedPropsForUser = getActualProps(['username', 'password'])
const getFormattedQueryParamsForUser = getActualProps(['_id', 'username'])
// Test
const fred = {_id: 1, name: 'fred', username: 'fflint', password: 'dino'}
const wilma = {_id: 2, name: 'wilma', username: 'wilma42'}
const barney = {_id: 3, name: 'barney', password: 'bam*2'}
console.log(getFormattedPropsForUser(fred)) //~> {password: "dino", username: "fflint"}
console.log(getFormattedQueryParamsForUser(fred)) //~> {_id: 1, username: "fflint"}
console.log(getFormattedPropsForUser(wilma)) //~> {username: "wilma42"}
console.log(getFormattedQueryParamsForUser(wilma)) //~> {_id: 2, username: "wilma42"}
console.log(getFormattedPropsForUser(barney)) //~> {password: "bam*2"}
console.log(getFormattedQueryParamsForUser(barney)) //~> {_id: 3}
<script src="https://bundle.run/ramda#0.26.1"></script><script>
const {pickBy, includes} = ramda </script>
Related
I don't know how to make a list of documents with mongoose (Node JS), someone know's how to make that?
new mongoose.Schema({
first_name: String,
last_name: String,
companies: [
{
name_company:String,
post:String,
time_in_post:String,
}
]
});
I need to insert many documents with companies schema at different times but I don't know how to make that with mongoose.
Can someone help me?
Seems like splitting this into different schemas might be a good idea. Especially if other people will be apart of the same company.
For instance, maybe you could try this:
const CompanySchema = new mongoose.Schema({
name: String,
// ... other company specific attributes
});
const Company = mongoose.model("Company", CompanySchema);
const UserSchema = new mongoose.Schema({
firstName: String,
lastName: String,
companies: [
{
company: { type: mongoose.Schema.Types.ObjectId, ref: 'Company' },
post: String,
timeInPost: String,
}
]
});
const User = mongoose.model("User", UserSchema);
And the interaction with the models could look like this:
(async () => {
try {
const company1 = await Company.create({ name: "Company 1" });
const company2 = await Company.create({ name: "Company 2" });
const user1 = await User.create({
firstName: "first",
lastName: "last",
companies: [
{
company: company1._id,
post: "....",
timeInPost: "....",
},
{
company: company2._id,
post: "....",
timeInPost: "....",
},
],
});
const users = await User.find({}).populate("companies.company"); // in order to populate the company with the document from the company collection
// users with companies info
} catch (error) {
console.log(error);
}
})();
Referenced from the mongoose documentation: https://alexanderzeitler.com/articles/mongoose-referencing-schema-in-properties-and-arrays/
You could use this approach, with this way you avoid data duplication:
const companySchema = new mongoose.Schema({
name_company: String,
post: String,
time_in_post: String
});
new mongoose.Schema({
firstName: String,
lastName: String,
companies: [companySchema] // Array of subdocuments
});
See full documentation here: https://mongoosejs.com/docs/guide.html
I'm trying to validate my target object with following conditions:
if (target.company === `GP` AND one of target.documents type equals `full`) {
one of target.documents type must equals `part-should-be-error`
} else {
throw new Error()
}
In this example, validation doesn't return any errors, but it should, because of 'part' !== 'part-should-be-error'
I tried https://stackoverflow.com/a/53647449/10432429 but it doesn't work with Joi v15
Since I can't merge array schema with alternative schema, all that I can to do is use $ to get global context, but seems that it doesn't work too
I have codebase on Joi v15.1.1, so please install same version
npm i #hapi/joi#15.1.1
const Joi = require('#hapi/joi');
(async () => {
const target = {
name: 'Jeff',
company: 'GP',
documents: [
{type: 'full', value: 'apple'},
{type: 'part', value: 'tesla'},
],
};
const documents = Joi.object().keys({
type: Joi.string().valid(['full', 'part', 'empty']),
value: Joi.string().min(1).max(40)
.required(),
}).required();
const schema = Joi.object()
.keys({
name: Joi.string().min(1).max(20)
.required(),
company: Joi.string().valid(['GP', 'QW']),
documents: Joi.array().items(documents).min(1)
.when('$', {
is: Joi.object().keys({
company: Joi.string().valid(['GP']),
documents: Joi.array().has(Joi.object({type: Joi.string().valid('full')}).unknown().required()),
}).unknown().required(),
then: Joi.array().has(Joi.object({type: Joi.string().valid(['part-should-be-error'])}).unknown()).required(),
})
.required(),
});
await Joi.validate(target, schema, {context: target});
})();
If I do sth wierd, please feel free to show another way how to solve this
I am trying to use an if/else and I can't figure out where I'm going wrong with the syntax. I want the payload to only submit school_ids if the role isn't p_admin. Thank you for your help!
const createUser = (payload) => request.postJSON(
'/register',
excludeObjNullValue({
username: payload.username,
email: payload.email,
password: payload.password,
first_name: payload.firstName,
last_name: payload.lastName,
role: payload.role,
district_id: payload.districtId,
if (role !== 'p_admin'){
school_ids: payload.schoolIds
}
})
);
I see 2-3 options depending on your excludeObjNullValue function:
You can either break that expression up in to a couple of statements, or
Or use property spread notation and the conditional operator, or
If excludeObjNullValue does what the name suggests, you can use a conditional without spread notation and rely on excludeObjNullValue to exclude it
Option 3 may well be your best bet, but I'll give them in order:
Option 1: The multi-statement way:
const createUser = (payload) => {
const options = {
username: payload.username,
email: payload.email,
password: payload.password,
first_name: payload.firstName,
last_name: payload.lastName,
role: payload.role,
district_id: payload.districtId,
};
if (role !== 'p_admin') {
options.school_ids = payload.schoolIds;
}
return request.postJSON('/register', excludeObjNullValue(options));
};
Option 2: Property spread and the conditional operator
Property spread is a Stage 3 proposal but support for it is already shipping in Chrome and Firefox, and if you're transpiling you can tell your transpiler to support it. That would look like this:
const createUser = (payload) => request.postJSON(
'/register',
excludeObjNullValue({
username: payload.username,
email: payload.email,
password: payload.password,
first_name: payload.firstName,
last_name: payload.lastName,
role: payload.role,
district_id: payload.districtId,
{...(role !== 'p_admin' ? {school_ids: payload.schoolIds} : {}}
}
})
);
Whether it's a good idea even if supported is your call. :-) It does briefly create an extra object and iterator.
Option 3: Rely on excludeObjNullValue to exclude properties with null values:
If it really does what the name suggests, then it will remove school_ids if we give the value null to it. So:
const createUser = (payload) => request.postJSON(
'/register',
excludeObjNullValue({
username: payload.username,
email: payload.email,
password: payload.password,
first_name: payload.firstName,
last_name: payload.lastName,
role: payload.role,
district_id: payload.districtId,
school_ids: role !== 'p_admin' ? payload.schoolIds : null
}
})
);
You can't write if statement at the object declaration. Also you need to explicitly defined body for your arrow function. So you can do something like
const createUser = (payload) => {
const obj = {
username: payload.username,
email: payload.email,
password: payload.password,
first_name: payload.firstName,
last_name: payload.lastName,
role: payload.role,
district_id: payload.districtId
};
if(obj.role !== 'p_admin') {
obj.school_ids = payload.schoolIds
}
return request.postJSON('/register', excludeObjNullValue(obj));
}
I want to create 4 new users,
let JonSnow = new User({ id: 1, name: 'Jon Snow', status: Status.user });
let AryaStark = new User({ id: 2, name: 'Arya Star', status: Status.user });
let SansaStark = new User({ id: 3, name: 'Sansa Stark', status: Status.user });
let JoffreyBaretheon = new User({ id: 4, name: 'Joffrey Baretheon', status: Status.user });
In my User class I have a allUser function,
allUsers() {
let users: IUser[] = [];
let user: IUser = {
id: this.id,
name: this.name,
status: this.status
}
users.push(user);
users.forEach((user) => console.log(user));
return users;
}
If I call the the function like so,
JonSnow.allUsers();
AryaStark.allUsers();
SansaStark.allUsers();
JoffreyBaretheon.allUsers();
It calls the allUsers function 4 times, as expected.
How would I store all 4 new users into one array? So I would only need to call the function once to show all users?
You can have a module/namespace variable (don't export it so it won't be accessible from outside), like so:
let users: IUser[] = [
new User({ id: 1, name: 'Jon Snow', status: Status.user }),
new User({ id: 2, name: 'Arya Star', status: Status.user }),
new User({ id: 3, name: 'Sansa Stark', status: Status.user }),
new User({ id: 4, name: 'Joffrey Baretheon', status: Status.user })
]
and then you have a simple method:
allUsers(): IUser[] {
return users.slice(0);
}
Notice that I cloned the users array so that who ever gets a reference to it won't be able to change this inner array, but it's not a must.
But there's no real need to have this method in all classes, you can make it static.
But you can also then make this array a static member of the User class, so:
class User {
private static users: IUser[] = [];
constructor() {
User.users.push(this);
}
static allUsers(): IUser[] {
return User.users.slice(0);
}
}
The you can get all users: User.allUsers().
It seems like you are just trying to convert a bunch of User instances into a single array of IUser objects.
What I would do is provide a User class method that returns an IUser object:
public toIUser():IUser {
return {
id: this.id,
name: this.name,
status: this.status
}
}
Then simply map your instances using that function:
let allUsers = [JonSnow, AryaStark, SansaStark, JoffreyBaretheon].map(user => user.toIUser());
console.log("all users:", allUsers);
Playground example here.
PS: I would avoid using static variables as your solution.
Declare static User variable as an array:
User.users = []
In User constructor add the current object to the array:
User.users.push(this)
Then in allUsers return the array:
allUsers() {
return User.users
}
I have a JavaScript data structure like the following in my Node.js/Express web app:
var users = [
{ username: 'x', password: 'secret', email: 'x#x.com' }
, { username: 'y', password: 'secret2', email: 'y#x.com' }
];
After receiving posted form values for a new user:
{
req.body.username='z',
req.body.password='secret3',
req.body.email='z#x.com'
}
I'd like to add the new user to the data structure which should result in the following structure:
users = [
{ username: 'x', password: 'secret', email: 'x#x.com' }
, { username: 'y', password: 'secret2', email: 'y#x.com' }
, { username: 'z', password: 'secret3', email: 'z#x.com' }
];
How do I add a new record to my users array using the posted values?
You can use the push method to add elements to the end of an array.
var users = [
{ username: 'x', password: 'secret', email: 'x#x.com' }
, { username: 'y', password: 'secret2', email: 'y#x.com' }
];
users.push( { username: 'z', password: 'secret3', email: 'z#x.com' } )
You could also just set users[users.length] = the_new_element but I don't think that looks as good.
You can add items to an array in many ways:
Push - adds to the end (think stack)
Unshift - adds to the beginning (think queue)
Splice - generic (push and unshift are wrappers around this)