build schema correct in mongoDB/mongoose - node.js

I'm trying to make a poll vote app.
My big problem is that I can't make an array of objects and access them. I try to make a few option votes to one poll like that:
title:"question?"
option:content:"1 answer",vote:0
content:"2 answer",vote:0
content:"3 answer",vote:...
and build schema like that:
var mongoose = require("mongoose");
var pollSchema = new mongoose.Schema({
title: String,
maker :{
id:{
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
},
options:[{content: String,vote:{type:Number,default:0}}]
});
module.exports = mongoose.model("Poll",pollSchema);
and get the data from there:
<div class="form-group" id="option">
<label for="Option 1">Options</label>
<input type="text" class="form-control" name="options[content]" placeholder="Option 1">
<input type="text" class="form-control" name="options[content]" placeholder="Option 2">
</div>
and the output in mongoDB is:
{
"_id": {
"$oid": "5993030dc5fa8c1b4f7eb176"
},
"title": "Some question?",
"options": [
{
"content": "opt 1,opt 2",
"_id": {
"$oid": "5993030dc5fa8c1b4f7eb177"
},
"vote": 0
}
],
"maker": {
"username": "Naor Malca"
},
"__v": 0
}
I want each option to have separate content, id and vote.
maybe i input the data worng?or the schema is worng?
UPDATE:
This my route code:
//NEW POLL ROUTE
app.post("/",function(req, res){
var title = req.body.title;
var options = req.body.options;
var maker = req.body.maker;
var newPoll = {title:title,options:options,maker:maker};
Poll.create(newPoll,function(err,poll){
if(err){
res.send("create error");
} else{
res.redirect("/");
}
});
});
still not working this the output:(its make the text an array not a array of objects...)
{ _id: 5993fcad9a63350df274b3e5,
title: '111',
__v: 0,
options: [ { text: '222,333', _id: 5993fcad9a63350df274b3e6, vote: '0' } ],
maker: { username: 'naor' } }

When you build your form, add [number] so that each option is different.
<div class="form-group" id="option">
<label for="Option 1">Options</label>
<input type="text" class="form-control" name="options[0][content]" placeholder="Option 1" value="value1">
<input type="text" class="form-control" name="options[1][content]" placeholder="Option 2" value="value2">
</div>
That way when you submit the form, it should come back as array of objects
req.body.options = [
{ content: 'value1' },
{ content: 'value2' }
]
This is a typical approach when you build an "add" form containing grouped elements.
--
When it comes to an "edit" form such that you want to update existing options, you can pass the option's _id
Here's an example using EJS
<div class="form-group" id="option">
<label for="Option 1">Options</label>
<% poll.options.forEach(option => { %>
<input type="text" class="form-control" name="options[<%= option._id %>][content]" placeholder="Option 1" value="<%= option.content %>">
<% }) %>
</div>
Here req.body.options should be an object
req.body.options = {
'some-id': {
content: 'value1'
},
'another-id': {
content: 'value2'
}
}
When you save, you would iterate over the object with the key i.e. _id. I think you can make use of id() to find the object to set.
--
If it doesn't come back in the formats mentioned above, you most likely need to use and set the bodyParser.

Related

Display (map) list of messages nested in an object (MERN)

I am learning MERN and would like to display the list of messages from Mongo Database in React UI.
My UserSchema in Mongo:
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
phone: {
type: Number,
required: true,
},
messages: [
{
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
phone: {
type: Number,
required: true,
},
message: {
type: String,
required: true,
},
},
],
tokens: [
{
token: {
type: String,
required: true,
},
},
],
});
Code in Home.js in React:
import React, { useState, useEffect } from "react";
const Home = () => {
const [userName, setUserName] = useState({});
const [show, setShow] = useState(false);
const userHome = async () => {
try {
const res = await fetch("/userdata", {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
const data = await res.json(); //successfully getting complete json data in console.
console.log(data);
setUserName(data);
setShow(true);
} catch (err) {
console.log(err);
}
};
useEffect(() => {
userHome();
}, []);
return (
<>
<div className="page-wrap d-flex flex-row align-items-center">
<div className="container">
<div className="row justify-content-center">
<div className="col-md-12 text-center">
<span className="display-1 d-block">
<p> Welcome {show ? "Back!" : ""} </p>
<h1>{userName.name}</h1>
<h2>
{show
? "What you want to do today?"
: "Your own Portal.."}
</h2>
</span>
<div className="mb-4 lead">
{show
? ""
: "You need to register and login for accessing your profile."}
</div>
<div>
<div>Messages:{userName[0].message}</div>
{/* wants to display list of all message here */}
</div>
</div>
</div>
</div>
</div>
</>
);
};
export default Home;
My approach to try fetching the list of all messages
I tried map method but not succeeded and tried below code still no success. Kindly advise. I want to display all the messages Message 1, Messag 2 etc. upon loading.
<div>Messages:{userName[0].message}</div>
Error Message in Browser:
TypeError: Cannot read properties of undefined (reading 'message')
I got it solved as below
Removed
<div>Messages:{userName[0].message}</div>
{/* wants to display list of all message here */}
</div>
Added:
<div>
{userName.messages?.map((msg1) => (
<li key={msg1._id}>{msg1.message}</li> ))}
</div>
can you delete this part:
<div>
<div>Messages:{userName[0].message}</div>
{/* wants to display list of all message here */}
</div>
and add this instead:
<div>{
data.map(result => (
<div key={result._id}>
<h2>{result.name}</h2>
<p>Some text: {result.messages}</p>
</div>
))
}</div>
If above code works, then you can tweak it to display your desired message which i think is this:
<p>Some text: {result.messages[0].message}</p>
Please let me know if it works.

how to update the single value in an array of objet with fetching object in the array by its id and how to fetch a single value from it

var agentSchema = new Schema({
datejoined: Date,
Agent: [{
name: String,
phone: String,
uniqueid: String,
state: String,
district: String,
fleet: String,
payment: String,
status: String,
hint: String
}],})
this is my mongoose data base code
i want access the array of object agent by id and update payment status,hit,fleet etc indiviually
Agent.update({ _id: req.query.person_id }).select({ agent: { $elemMatch: { _id: req.query.object_id } } }).then(
res.redirect('/admin/agentrequest')).catch(err => console.log(err));
i triedt to fetch it some how like this but i am not able to update the value
<% for (let doc of prods) { %>
<form method="POST" action="/admin/editbus" class="user">
<div class="form-group row">
<div class="col-sm-12 mb-3 mb-sm-0">
<label for="status">status</label>
<input type="text" name="status" class="form-control form-control-user" list="status" id="exampleFirstName" placeholder="<%= doc.status %>">
<datalist id="status">
<option value="Pending">
<option value="Accepted">
<option value="Rejected">
<option value="Waiting for change">
<option value="Verifying">
</datalist>
</div>
</div>
<input type="hidden" name="_id" value="<%= doc._id %>">
<input type="submit" value="change" class="btn btn-primary btn-user btn-block col-sm-12 mb-3 mb-sm-0">
</input>
</form>
<% } %>
<hr>
here is my ejs
Agent.update({ 'agent._id': req.body.id }, {
'$set': {
'agent.$.phone': req.body.phone,
}
}).then(
res.redirect('/admin/agentrequest')).catch(err => console.log(err));
i also tried this way
enter code here
Agent.findOneAndUpdate({ _id: req.body.agent_id, bus: { $elemMatch: { _id: req.body.object_id } } }, {
$set: {
'agent.$.phone': req.body.phone,
'agent.$.uniqueid': req.body.registration,
}
}, // list fields you like to change
{ 'new': true, 'safe': true, 'upsert': true }).then(
thank you turvishal but this code works for me

2checkout Payment Authorization Failed in React

I have been using 2checkout payment gateway. I am using the script file provided by 2checkout. First I was importing it in my index.html file by using <link></link> and it was giving me an CORBS error. So I downloaded the script and place in local file.
Now, it's working as expected. It's providing me with authorization token by 2checkout. Following is my component that I have been using to get token form server.
import React, { useEffect, useState } from 'react';
const Form = (props) => {
const [ card, setCard ] = useState({
sellerId: <my-seller-id>,
publishableKey: <my-publishable-key>,
ccNo: '',
expMonth: '',
expYear: '',
cvv: ''
});
const [ returnToken, setReturnToken ] = useState(null);
useEffect(() => {
window.TCO.loadPubKey('sandbox');
}, []);
const submitted = (e) => {
e.preventDefault();
var payWithCard = (data) => {
console.log(data.response.token.token);
};
var error = (error) => {
console.log(error);
};
try {
window.TCO.requestToken(payWithCard, error, card);
} catch (error) {
setTimeout(() => {
window.TCO.requestToken(payWithCard, error, card);
}, 3000);
}
};
const change = (e) => {
setCard({
...card,
[e.target.name]: e.target.value
});
};
return (
<form id="tcoCCForm" onSubmit={submitted}>
<input id="sellerId" type="hidden" value={card.sellerId} />
<input id="publishableKey" type="hidden" value={card.publishableKey} />
<div>
<label>
<span>Card Number</span>
<input
id="ccNo"
name="ccNo"
type="text"
value={card.ccNo}
autoComplete="off"
required
onChange={(e) => change(e)}
/>
</label>
</div>
<div>
<label>
<span>Expiration Date (MM/YYYY)</span>
<input
type="text"
size="2"
id="expMonth"
name="expMonth"
value={card.expMonth}
required
onChange={(e) => change(e)}
/>
</label>
<span> / </span>
<input
type="text"
size="4"
id="expYear"
name="expYear"
value={card.expYear}
required
onChange={(e) => change(e)}
/>
</div>
<div>
<label>
<span>CVC</span>
<input
id="cvv"
name="cvv"
type="text"
value={card.cvv}
autoComplete="off"
required
onChange={(e) => change(e)}
/>
</label>
</div>
<input type="submit" />
</form>
);
};
export default Form;
so, it's giving me the token to console that I am using in Postman for testing the 2checkout api.
https://www.2checkout.com/checkout/api/1/<seller_id>/rs/authService
I have been using following payload to send the POST request to this api.
{
"sellerId": <seller_id>,
"privateKey": <private_key>,
"merchantOrderId": "123",
"token": "N2Y5MDFmNTItYzcxMS00OGQ5LTk2MmItOGJlMjAzYWQwNDFl",
"currency": "USD",
"demo": true,
"lineItems": [
{"name": "Package A", "price": 10, "quantity": 1, "type": "product", "recurrence": "1 Month", "duration": "Forever"} ],
"billingAddr": {"name": "Wasi Ullah", "addrLine1": " village Bharaj P/O Lakhanwal", "city": "Gujrat", "state": "Pubjab", "zipCode": "50700", "country": "Pakistan", "email": "chwasiullah#gmail.com", "phoneNumber": "+923006242851"}
}
While the response I got everytime is:
{
"validationErrors": null,
"response": null,
"exception": {
"exception": false,
"httpStatus": "400",
"errorMsg": "Payment Authorization Failed: Please verify your information and try again, or try another payment method.",
"errorCode": "607"
}
}
Even I have provided with original card and all information in demo mode. But there's still the same issue.
I got the solution to this problem. I want to share it. May be it will be helpful for you.
If you are testing 2checkout don't forget to check the documentation of test orders:
https://knowledgecenter.2checkout.com/Documentation/09Test_ordering_system/01Test_payment_methods
Moreover, I wasn't adding the name according to this test order in api that's why it was saying me that Card Authorization failed.

How to add a key value pair on existing object created via Vue Reactivity

I already have an existing form which is dynamically created. However, I have problems with regards to adding a new set of key value pairs to the existing object. I have used the Vue Reactivity using the this.$set() method with success on the FIRST pair only.
Output
{ "traveller_1": { "gender": "c" },
"traveller_2": { "gender": "f" },
"traveller_3": { "gender": "i" }
}
Expected Output
{ "traveller_1": { "firstname": "John", "age": "23", "gender": "m" },
"traveller_2": { "firstname": "Jane", "age": "21", "gender": "f" },
"traveller_3": { "firstname": "Jade", "age": "25", "gender": "f" },
}
Fiddle https://jsfiddle.net/stda7Lwm/
View
<div class="col-md-10" id="app"> {{ travellerDetails }}
<div class="form-row" v-for="i in travellers">
<div class="form-group col-md-6" v-for="(details, index) in bookingRequiredDetails">
<label for="required-details">{{ details }}</label>
<input
type="text"
class="form-control"
#input="prop('traveller_' + i, details, $event)"
placeholder="Required Details"
/>
</div>
</div>
</div>
JS
new Vue({
el: '#app',
mounted () {
},
data () {
return {
test: { 'unit1' : { life: 30}},
travellerDetails: { },
travellers: 3,
bookingRequiredDetails: ['fullname', 'age', 'gender'],
};
},
methods: {
prop: function(obj, prop, event) {
this.$set(this.travellerDetails, obj, { [prop] : event.target.value } );
console.log(this.travellerDetails);
}
},
})
You're overriding all object every time you assign new value. You should change a single prop only
prop: function(obj, prop, event) {
const data = this.travellerDetails[obj] || {}
data[prop] = event.target.value
this.travellerDetails = {
...this.travellerDetails,
[obj]: {...data}
}
}

Save/design nested form to save/update data in mongodb via mongoose according to mongoose schema

I have created the following mongoose schema for saving a quiz in mongodb -
var answerSchema = new Schema({
answer: String,
correct: Boolean
});
var questionSchema = new Schema({
title: String,
tag: String,
chapterName: String,
marks: Number,
negativeMarks: Number,
correctAnswerExplanation: String,
hint: String,
answers: [answerSchema]
});
var quizSchema = new Schema({
courseId: Number,
courseName: String,
lectureId: Number,
lectureName: String,
popupTime: Number,
teacherName: String,
questions: [questionSchema]
});
var Quiz = mongoose.model('quiz', quizSchema );
I am able to store the hard coded values in the following way -
var quiz1 = new Quiz({
courseId: 4,
lectureId: 5008,
popupTime: 3,
teacherName: 'Charles Xavier',
questions: [
{
"title": "Which is the Capital of India " ,
"answers": [
{ "answer": "Delhi", "correct": true },
{ "answer": "Bangalore", "correct": false },
{ "answer": "Mumbai", "correct": false },
{ "answer": "Chennai", "correct": false }
]
},
{
"title": "Where is facebook hosted? " ,
"answers": [
{ "answer": "Heroku", "correct": true },
{ "answer": "Digital Ocean", "correct": false },
{ "answer": "AWS", "correct": true },
{ "answer": "SWF", "correct": false }
]
}
]
});
quiz1.save(function(err, q) {
console.log("Saved ----");
console.log(q);
res.json(q);
});
This works perfectly fine.
Now which is the best way to create a GUI form so that when the user fills in the details, it is converted to json and it is saved in mongodb via mongoose.
I have come up with the following form -
<form id="aj">
<input type="text" name="questions[0]" value="" placeholder="Question Title">
<input type="text" name="answers[0]" value="" placeholder="Answer 1">
<input type="text" name="answers[1]" value="" placeholder="Answer 2">
<input type="text" name="answers[2]" value="" placeholder="Answer 3">
<input type="text" name="answers[3]" value="" placeholder="Answer 4">
<button>Send</button>
</form>
And on form submit I serialize the form data using this snipped -
var o = {};
var a = $( "#aj" ).serializeArray();
$.each(a, function() {
if (o[this.name]) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
And in the express route handler I am saving it in the similar way -
This is what I get in the request body via express -
{ questions: [ 'Q 1' ],
answers: [ ' A 1', 'A 2', 'A 3', 'A 4' ] }
var quiz = req.body(i.e the above object)
var add = new Quiz(quiz);
add.save(function(err, quiz) {
if(err) {
console.log(err);
} else {
console.log("Saved");
console.log(quiz);
}
});
But I am getting the following error -
[TypeError: Cannot use 'in' operator to search for '_id' in Q 1]
How do I solve this, please help as I just started with mongodb and mongoose and I come from a SQL background.
Also, how should I design a form that takes inputs of multiple questions and each question can have multiple answers and each answer has a bit to indicate whether it is correct answer or not.

Resources