Inquirer.js populate list choices from sql database - javascript

I"m using inquirer.js to build a commandline employee database.
Is it possible to populate the choices array dynamically from a sql database in inquirer.js?
for example
inquirer.prompt([
{ type: 'list',
message: "Choose department to add Role to",
name: "department",
choices: [
`SELECT * FROM departments`
]
}
])
deparments is the table I want to acceess
I'd want it to return the list of all departments as the choices

I actually ran into this exact problem recently and have a functioning solution!!
Inquirer's choices key can be defined using a function but expects the function to return an array of objects; each object represents a choice and has a name: key to be shown to the user as an option for the choice, and a value: key which will be what inquirer stores as the answer value in the answer object (like a number, string, or boolean etc.). Here is an example of a structure the choices key expects to be returned from the function:
[
{
name: 'Choice 1',
value: 1,
},
{
name: 'Choice 2',
value: 'Something',
},
{
name: 'Choice 3',
value: false,
}
]
Make sure that you check the data that your function returns and ensure that you have this format so that inquirer's choice key accepts it!
Here is how I implemented it with a database:
I am using a .promise() on my connection so that I can use async/await syntax. Here is my connection setup for mysql2:
// use .promise() so that we can use await on connection
const connection = mysql.createConnection({
host: 'localhost',
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: 'employees_db',
}).promise();
Here is the particular question object that has choices: being defined by a function called departmentChoices() that is getting all the department choices from mysql database. Make sure this is defined in an async function as well so you can use await.
{
message: "Which Department's budget do you want to see?",
name: 'id',
type: 'list',
choices: await departmentChoices(),
when(answers) {
return answers.task === 'View a Department Budget';
},
},
Here is the function definition. I chose to use async/await for the database query for easy of readability. You should probably wrap it in a try/catch for better error handling and best practices. Notice I used an alias value for the id as this is the value I want to use for the value: key in the choice object. name did not need an alias as it is the value I want stored under the name: key in the choice object.
const departmentChoices = async () => {
const departmentQuery = `SELECT id AS value, name FROM department;`;
const departments = await connection.query(departmentQuery);
return departments[0];
};
This is the array this function will return from my database:
[
{ value: 1, name: 'Hair and Makeup' },
{ value: 2, name: 'Finance' },
{ value: 3, name: 'Set Design' },
{ value: 4, name: 'Wardrobe' }
]

Related

Is there a way to update an object in an array of a document by query in Mongoose?

I have got a data structure:
{
field: 1,
field: 3,
field: [
{ _id: xxx , subfield: 1 },
{ _id: xxx , subfield: 1 },
]
}
I need to update a certain element in the array.
So far I can only do that by pulling out old object and pushing in a new one, but it changes the file order.
My implementation:
const product = await ProductModel.findOne({ _id: productID });
const price = product.prices.find( (price: any) => price._id == id );
if(!price) {
throw {
type: 'ProductPriceError',
code: 404,
message: `Coundn't find price with provided ID: ${id}`,
success: false,
}
}
product.prices.pull({ _id: id })
product.prices.push(Object.assign(price, payload))
await product.save()
and I wonder if there is any atomic way to implement that. Because this approach doesn't seem to be secured.
Yes, you can update a particular object in the array if you can find it.
Have a look at the positional '$' operator here.
Your current implementation using mongoose will then be somewhat like this:
await ProductModel.updateOne(
{ _id: productID, 'prices._id': id },//Finding Product with the particular price
{ $set: { 'prices.$.subField': subFieldValue } },
);
Notice the '$' symbol in prices.$.subField. MongoDB is smart enough to only update the element at the index which was found by the query.

How to object property parse to nested array array using javascript?

It receives data from the request body in the following format. Properly I have to insert it into the database but the format is not correct.
{
name: '123',
description: 'Dev',
"item_variants[0]['name']": '23434',
"item_variants[0]['quantity']": '12334',
"item_variants[0]['unit_price']": '123123',
}
And how to transform the following format? Everyone's answers help me some ideas. Thank you
{
name: '123',
description: 'Dev',
item_variants: [
{
name: '23434',
quantity: '23434',
unit_price: '23434',
}
]
}
In express, after getting this form body you have to store this response in any variable and reformate this response after formatting you can save it into the database.
try {
let inputs = req.body;
inputs = {
name: inputs.name,
description: inputs.description,
item_variants: [
{
name: item_variants[0].name,
quantity: item_variants[0].quantity,
unit_price: item_variants[0].unit_price,
},
],
};
// NOW you can save this formatted version into the database
const result = await Product.save(inputs);
} catch (e) {
console.log(e);
}
In item_variants name, quantity, unit_price you might change digging and getting value.

Normalizr - is it a way to generate IDs for non-ids entity model?

I'm using normalizr util to process API response based on non-ids model. As I know, typically normalizr works with ids model, but maybe there is a some way to generate ids "on the go"?
My API response example:
```
// input data:
const inputData = {
doctors: [
{
name: Jon,
post: chief
},
{
name: Marta,
post: nurse
},
//....
}
// expected output data:
const outputData = {
entities: {
nameCards : {
uniqueID_0: { id: uniqueID_0, name: Jon, post: uniqueID_3 },
uniqueID_1: { id: uniqueID_1, name: Marta, post: uniqueID_4 }
},
positions: {
uniqueID_3: { id: uniqueID_3, post: chief },
uniqueID_4: { id: uniqueID_4, post: nurse }
}
},
result: uniqueID_0
}
```
P.S.
I heard from someone about generating IDs "by the hood" in normalizr for such cases as my, but I did found such solution.
As mentioned in this issue:
Normalizr is never going to be able to generate unique IDs for you. We
don't do any memoization or anything internally, as that would be
unnecessary for most people.
Your working solution is okay, but will fail if you receive one of
these entities again later from another API endpoint.
My recommendation would be to find something that's constant and
unique on your entities and use that as something to generate unique
IDs from.
And then, as mentioned in the docs, you need to set idAttribute to replace 'id' with another key:
const data = { id_str: '123', url: 'https://twitter.com', user: { id_str: '456', name: 'Jimmy' } };
const user = new schema.Entity('users', {}, { idAttribute: 'id_str' });
const tweet = new schema.Entity('tweets', { user: user }, {
idAttribute: 'id_str',
// Apply everything from entityB over entityA, except for "favorites"
mergeStrategy: (entityA, entityB) => ({
...entityA,
...entityB,
favorites: entityA.favorites
}),
// Remove the URL field from the entity
processStrategy: (entity) => omit(entity, 'url')
});
const normalizedData = normalize(data, tweet);
EDIT
You can always provide unique id's using external lib or by hand:
inputData.doctors = inputData.doctors.map((doc, idx) => ({
...doc,
id: `doctor_${idx}`
}))
Have a processStrategy which is basically a function and in that function assign your id's there, ie. value.id = uuid(). Visit the link below to see an example https://github.com/paularmstrong/normalizr/issues/256

access object in array for POST method

I am creating a POST method via mongo/mongoose:
Department
.create({
name: req.body.name,
link: req.body.link,
state: req.body.state,
requirements: req.body.requirements,
salary: req.body.salary,
description: req.body.description
})
requirements is an object containing other items:
requirements: {
age: 21,
citizenship: "yes",
degree: "4-year"
}
Prior to creating I am checking that all fields were provided:
router.post('/create', (req, res) => {
const requiredFields = ["name", "link", "state", "age", "citizenship", "degree" "salary", "description"];
for(let i=0; i < requiredFields.length; i++){
const field = requiredFields[i];
if(!(field in req.body)){
const message = `Missing \`${field}\` field in request body`;
console.error(message);
return res.status(400).send(message);
};
};
Due to age, citizenship, and degree being object items, I cannot put their string inside the requiredFields. It errors out at Missing age field in request body. Any idea how to check that they were provided in req.body?
To access the nested object you may save your required field as "requirement.age" instead of "age" and then may be use the get function in lodash library. So your condition would become:
`
if (typeof(_.get(req.body, "requirement.age") === 'undefined')) {
//Missing field
}
`
You can try to flatten the req.body structure like:
Object.assign(req.body, req.body.requirement)
// This would make your req.body look like
{
name: 'x',
link: 'y',
requirement: {
age: 1
..
},
age: 1
..
}
Or you may assign it to another variable and then use.
let reqBodyReplica = Object.assign({}, req.body, req.body,requirement)

How to extend/modify the object in nodejs api?

i am using the angular-fullstack yeoman generator. created a schema for a Product, and a set of api crud operations. all works well. now in the get list operations, i don't want to receive all the fields, only a subset. like a select in sql. i would also wish to alter one value. instead of the price, i need price * 1.1 .
how to do that?
here is the code for the index method (returns list of products):
// Gets a list of Products
export function index(req, res) {
Product.findAsync()
.then(respondWithResult(res))
.catch(handleError(res));
}
function respondWithResult(res, statusCode) {
statusCode = statusCode || 200;
return function(entity) {
if (entity) {
res.status(statusCode).json(entity);
}
};
}
As stated in the documentation, .find() takes two params, query and projection.
// params
Product.findAsync(query, projection)
You can use projection to "select" a subset of fields;
// example
Product.findAsync({}, { _id: 1, name: 1, description: 1 })
// result, only the three specified field will be returned
[
{ _id: 'abc123', name: 'Some name', description: 'Some description'},
{...}
]
If you want to manipulate data I think you have to use the aggregation pipeline

Categories

Resources