push array of strings to mongoDB with mongoose - javascript

I am not sure how to go about saving an array of strings from an input field to mongoDB with mongoose.
Ideally I would like to enter text several times in the same input field that creates an array. So I would end up having something like this.
title: "This is my Title"
actions: [ "walking", "smiling", "laughing"]
EJS File:
<form action="/blogs" method="POST">
<input type="text" placeholder="title" name="title" id="title" >
<input type="text" name="actions" id="actions" >
<button >submit</button>
</form>
blog.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const blogSchema = new Schema(
{
title: {
type: String,
required: true,
},
actions: [
{
type: String,
},
],
},
{ timestamps: true }
);
const Blog = mongoose.model("Blog", blogSchema);
module.exports = Blog;
app.js
app.post('/blogs', (req, res) => {
const blog = new Blog ({
title: req.body.title,
actions: req.body.tags,
});
blog.save()
.then((result) => {
res.redirect('/blogs')
})
.catch((erro) => {
console.log(erro)
})
})
Any guide on how to approach this? Right now my only solution is to create multiple input fields, but that is not correct.

If the actions tags are predefined and specific you can use html select multiple. That way actions property will be sent as an array of strings
<form action="/blogs" method="POST">
<input type="text" placeholder="title" name="title" id="title" >
<label for="actions">Actions:</label>
<select name="actions" id="actions" multiple>
<option value="walking">walking</option>
<option value="smiling">smiling</option>
<option value="laughing">laughing</option>
</select>
<button >submit</button>
</form>
And inside the controller you handle this way
// req.body.actions is already an array.
const blog = new Blog(req.body);
blog.save()
.then((result) => {
res.redirect('/blogs')
})
.catch((erro) => {
console.log(erro)
})
If, in any case, you want to use a text input to write the actions separated by space or comma, the actions property will be sent as a string. Then you can convert the string to array inside the controller.
// In case of multiple spaces, replace with single space.
// Then split string to array of strings
let actions = req.body.actions.replace(/ +/g, " ").split(" ")
const blog = new Blog ({
title: req.body.title,
actions
});
// rest of code
Whatever you choose to do, the actions will be stored as array of strings in the database.

Possibly you are sending an array as a string to the mongo. You can check this by checking the type of req.body.tags like so:
console.log(typeof req.body.tags)
If this returns a String, make sure you send the content as JSON to the database.

Related

Is there a way to destructure and access the middle elements?

On a React component I have a form that, when submitted, calls the following function, where I want to extract the data from the form:
const onSubmitFormData = (event) => {
// 1. Manual way
const formData = {
name: event.target.name.value,
email: event.target.email.value,
password: event.target.password.value,
}
// 2. Automated way??
const {name: {value}, email, password} = event.target.${}.value;
//...
}
What I wanted was to use destructuring to get the values from the ids on the form. The problem is that, for each id, I have to get id.value. And if there were 1000 fields on the form, it would be tedious and error prone to write the code as in the manual way...ofc I'm assuming there would be someone willing to fill that 1000-field form!
Jokes aside, is there a way to do this with destructuring or any similar way?
You can do it just by adding one line of code that:
Generates an array of elements with Object.values(form)
map each element to => [key, value]
So for element el it's el => [el.name, el.value]
Creates an object from that array with Object.fromEntries()
If the variable form references the form element then the line is:
Object.fromEntries(Object.values(form).map(el => [el.name, el.value]))
Then destructure away!
function logValues(e){
e.preventDefault();
const form = e.target
const formData = Object.fromEntries(Object.values(form).map(el => [el.name, el.value]))
const {name, email, password} = formData
console.log(`
Name: ${name}
Email: ${email}
Password: ${password}`)
}
<form id="test" onsubmit={logValues(event)}>
<input name="name" placeholder="Name">
<input name="password" placeholder="Password">
<input name="email" placeholder="Email">
<button>Log Values</button>
</form>

Can't run UpdateDoc function when using Redux and FireBase

PersonalSlice.js
export const updatePersonal = createAsyncThunk("personal/updatePersonal", async (id, {getState})=>{
const personalDoc = doc(db, "Personal", id)
await updateDoc(personalDoc, getState().personal.updatePersonal );
});
Main.js
const updateName = useSelector((state) => state.personal.updatePersonal.name);
const handleUpdateNameChange = (e) => {
dispatch(changeUpdatePersonalName(e.currentTarget.value))
}
const handleUpdateSubmit = (e) => {
e.preventDefault();
dispatch(updatePersonal({updateName , updateSurname, updateBirthday, updateStartDate, updateDepartment, updatePhone, updateMail}))
}
<Form onSubmit={handleUpdateSubmit}>
<p className="text-center" style={{ color: "#39ace7" }}>İsim</p>
<Form.Control
size = "sm"
type="text"
name="updatePersonal"
onChange={handleUpdateNameChange}
value={updateName}
required
autoFocus
/>
I can't send the data I want to update in the form to FireBase. My fault is most likely in the parameters.
If you are starting a new project and/or are not required to have your Firebase data loaded into redux, you might want to give reactfire a try before trying react-redux-firebase. In reference to the above function call ,if the profile object contains a key or a list of keys as parameters, you can populate those parameters with the matching value from another location on firebase.
Setting config like this:
userProfile: 'users', // where profiles are stored in database
profileParamsToPopulate: [
'contacts:users'
]
}
Results in profile with populated contacts parameter:
displayName: 'ABC',
email: 'abc#xyz.com',
contacts: [
{
email: 'efg#xyz.com',
displayName: 'EFG'
},
{
email: 'pqr#xyz.com',
displayName: 'PQR
}
]
}
Please check the link here to understand the parameters call usage and related questions Update Data in Firebase and Update function in Firebase for reference.Also check the helpful documentation for configuration for redux-firebase

Image to Base64 with NodeJS (Express)

I'm doing a test, and I need to convert an image to base64 to store in my DB
forget about DB, I just need the base64 as a string.
This is my form:
<form action="/cadastrado" method="POST">
<! -- other irrelevants inputs -->
<input type="file" name="input_file" id="input_file" onchange="converterParaBase64()" required><br>
<button type="submit" onclick="base64()">CADASTRAR</button>
</form>
This is my route after submit the form:
app.post("/cadastrado", (req, res) => {
const {input_nome, input_telefone, input_cpf, input_email, input_file} = req.body;
console.log(req);
return res.json({
nome: input_nome,
telefone: input_telefone,
cpf: input_cpf,
email: input_email,
// base64image: input_file.toBase64 (I need something like this)
});
});
I'm doing greate about using the strings inputs, like nome, telefone, cpf and email (variables in PT-BR)
But I can't say the same with input_file
When I console.log(req.body) i get this:
{
input_nome: '1',
input_telefone: '2',
input_cpf: '3',
input_email: '4',
input_file: 'levia.jpg'
}
I need to convert this levia.png image into base64 as a string.
How I can do it ?
UPDATE 1:
Seems like the image in json, is just the file name.
It is possible to convert in client-side and after send to server-side ?
Try this
var fs = require('fs');
app.post("/cadastrado", (req, res) => {
const {input_nome, input_telefone, input_cpf, input_email, input_file} = req.body;
console.log(req);
var bitmap = fs.readFileSync(input_file);
var base64File = new Buffer(bitmap).toString('base64');
return res.json({
nome: input_nome,
telefone: input_telefone,
cpf: input_cpf,
email: input_email,
base64image: base64File
});
});
so I figured out how to resolve my problem.
Kind of vicarious what I did. I don't know if in future this can result in a problem, so I want to share with you.
Basically I create a input and edit his value in client side. Of course, I don't want a big input with a Base64 code messing with my poor HTML, so I styled with display: none. This input is inside the form, and it is sent to my req.body.
Snippets
index.html page with form:
...
<input type="file" id="input_file" name="input_file" onchange="convBase64()" required />
...
script.js with some logic
...
document.getElementById('input_base64').value = `${stringBase64}`;
...
css to hide the input with encoded image:
#input_base64 {
display: none;
}
This invisible input is inside the form. When the form is submitted, the input value is sent to body of request.

Returning data to nested field from computed

I am creating a blog article creation field, in which each field is gathered into fields: {} object.
data: {
fields: {
title: '',
slug: ''
}
},
I want to take the title and use a slugify method on that value, from which the computed should return the end-slug into the slug input.
This would work on a non-nested field:
computed: {
slug: function () {
return this.slugify(this.fields.title)
}
},
How can I access the nested field from computed?
Inputs:
<input type="text" class="form-control"
v-model="fields.title" placeholder="Enter your title">
<input v-model="fields.slug" type="text" class="form-control" disabled>
I need to use v-model on both inputs.
This works well and i get the slug, the problem is is that the data in fields.slug is not changing. How do I get my computed slug value into my fields.slug?

Dynamically pick values from req.body based on database attributes

I am building an app usine Node/EJS/Mongo where the user is building a capability survey, and needs to set the desired level for each question. The form that they use to pick the levels has a series of selects that look like:
<select class="form-control col-sm-4" id="<%=capability.capabilityId%>" name="<%=capability.capabilityId%>">
<option value=1>Developing</option>
<option value=2>Intermediate</option>
<option value=3>Advanced</option>
<option value=4>Role Model</option>
</select>
When the user then submits this form, I want to update the assessment to load in these expected levels.
The schema for assessments in my mongodb looks like:
var assessmentSchema = new mongoose.Schema ({
title: String,
startDate: Date,
endDate: Date,
behaviours: [{
behaviourName: String,
behaviourId: String,
order: Number,
capabilities: [{
orderCap: Number,
capabilityId: String,
capabilityName: String,
capabilityDesc: String,
developing: String,
intermediate: String,
advanced: String,
roleModel: String,
expectedLevel: Number,
motivation1: String,
motivation2: String,
motivation3: String,
motivation4: String,
motivation5: String
}] //capabilities object
}],
targetEmployees:[{
type: mongoose.Schema.Types.ObjectId,
ref: "Users"
}] //behaviours object
});
What I am thinking is I want to loop through all the capabilities, find the entry in req.body that has a name that matches capabilityId, and then update desiredLevel. I just can't see how to make it work. My route code currently looks like:
router.put(':id/levels', function(req, res) {
Assessment.findById(req.params.id, function(err, foundAssessment) {
foundAssessment.behaviours.forEach(function(b) {
b.capabilities.forEach(function(c) {
c.expectedLevel = req.body.SOMETHINGHERE
});
});
foundAssessment.save(function(err) {
if (err) {
console.log(err);
req.flash("error", err.message);
res.redirect("back");
} else {
// Send json back to xhr request
res.json(foundAssessment);
}
});
});
});
You can read request body dynamic attributes like this:
req.body[variable];

Categories