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
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.
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
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.
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}
}
}
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.