I have a complicated problem with my Node/React app. I have a shopping cart with the final element when checking out is to add order details to my MySQL database, however my function is returning an error from the controller. I am posting the relevant code, the full code is too extensive for a post.
This is the Node route:
module.exports = function(app) {
var controller = require('../controllers/controller');
// controller Routes
app.route('/products')
.get(controller.list_all_products)
.post(controller.create_a_product);
app.route('/products/:product_type')
.get(controller.products_by_type);
app.route('/product/:productId')
.get(controller.read_a_product)
.put(controller.update_a_product)
.delete(controller.delete_a_product);
};
This is the relevant part of the controller:
exports.create_a_product = function(req, res) {
var new_product = new Product(req.body);
//handles null error
if(!new_product.product || !new_product.status){
res.status(400).send({ error:true, message: 'Please provide product/status' });
} else {
Product.createProduct(new_product, function(err, product) {
if (err)
res.send(err);
res.json(product);
});
}
};
The relevant part of the Model:
var Product = function(product){
this.product = product.product;
this.status = Product.status;
this.created_at = new Date();
};
Product.createProduct = function (newProduct, result) {
sql.query("INSERT INTO orders set ?", newProduct, function (err, res) {
if(err) {
console.log("error: ", err);
result(err, null);
}
else{
console.log(res.insertId);
result(null, res.insertId);
}
});
};
Then the React side uses this api call:
import $ from 'jquery'
export const addOrder = order => {
const urlString = "http://localhost:9000/products"
return $.ajax({
url: urlString,
method: "POST",
data: order,
success: () => {
console.log('order logged')
},
error: (status, err) => {
console.log(status)
}
})
}
And finally I make the call with this var:
var r = await addOrder(this.state.order).then(res => res.json())
The order details are a simple object:
this.state = {
order: {
oid: '',
order_date: '',
products: '',
first_name: '',
last_name: '',
email: '',
address: '',
city: '',
province: '',
zip: '',
country: ''
}
}
When executing I get the error 'Please provide product/status' from the controller.
I know this is a tough one, any help is hugely appreciated.
It seems to me that you send the order object to products service which may contain multiple products. You should extract products from the order object (req.body) and send them to createProduct method in a loop.
Related
i made a quiz where you can test yourself then get a score, clicking on the button send score will submit the score to database.
My Goal: i need to send a Quiz score to database. I already added in model the score and in controller.js too, but i have no clue how to send score value to my database.
I tested with postman and it works perfectly, i received my score in my database, all what is remaining is the frontend part.
Backend:
FormController.js :
const form = require('../models/FormModel')
module.exports = {
store: (req, res, next) => {
let candidate = new form({
fname: req.body.fname,
lname: req.body.lname,
score: req.body.score
})
if (req.file) {
candidate.cv = req.file.path
}
candidate.save()
.then(response => {
res.json({
success: true,
message: 'Candidate added successfully!',
data: candidate,
})
})
.catch(error => {
res.json({
success: false,
message: 'An error occured!',
error: error,
})
})
}
}
FormModel.js:
const mongoose = require('mongoose')
const Schema = mongoose.Schema
const formSchema = new Schema({
fname: {
type: String
},
lname: {
type: String
},
score: {
type: Number
}
}, { timestamps: true })
const form = mongoose.model('form', formSchema)
module.exports = form
Frontend:
Quiz.js:
const finishQuiz = () => {
if (Questions[currQuestion].answer === optionChosen) {
setscore(score + 1);
}
setGameState("endScreen")
//maybe i need to add onclick event here?
}
I am currently developing a Pokemon Team Builder app with a React frontend and an Express backend with MongoDB for the database.
As far as I can tell my TeamSchema has no such atomic operators? Here is my TeamSchema:
const mongoose = require('mongoose');
const TeamSchema = new mongoose.Schema({
name: {
type: 'String',
required: true,
unique: true,
},
team: [
{
name: { type: String },
types: [{ type: String }],
sprite: { type: String },
},
],
username: {
type: String,
required: true,
},
userId: {
type: String,
required: true,
},
});
const TeamModel = mongoose.model('Team', TeamSchema);
module.exports = TeamModel;
And the error gets thrown in this method when I attempt to call the findOneAndReplace method by finding a team that has a name and userId match.
const replaceTeam = async (req, res) => {
const { teamName: name, filteredTeam: team } = req.body;
const { username, _id: userId } = req.user;
const newTeam = new Team({ name, team, username, userId });
try {
const replacedTeam = await Team.findOneAndReplace({ name, userId }, newTeam);
console.log(replacedTeam);
res.status(200).json({ message: 'Team was successfully overwritten!' });
} catch (err) {
console.log(err);
res.status(500).json({ message: 'An error occurred while updating the team.' });
}
};
This has been a real headscratcher here and I am not sure what is going wrong here. I have only started using mongoose a couple of weeks ago, so I wonder if it's something fundamental I am misunderstanding here.
The Mongoose function findOneAndReplace expects a document object passed in. See the below code.
details.findOneAndReplace(
{ location: "New York" },
{ name: "Sunny", age: 292, location: "Detroit" },
function(err, result) {
if (err) {
res.send(err);
} else {
res.send(result);
}
}
);
Change
const newTeam = new Team({ name, team, username, userId })
to
const newTeam = {name, team, username, userId}
Also as in the other poster's code, add the new: true option to the call as follows by changing
const replacedTeam = await Team.findOneAndReplace({ name, userId }, newTeam);
to
const replacedTeam = await Team.findOneAndReplace({ name, userId }, newTeam, { new: true });
otherwise the original document will be returned into replacedTeam
You can just use findOneAndUpdate and update all the fields with new data. You can do it like this:
const replaceTeam = async (req, res) => {
const { teamName: name, filteredTeam: team } = req.body;
const { username, _id: userId } = req.user;
try {
const replacedTeam = await Team.findOneAndUpdate({ name, userId }, { name, team, username, userId }, {new: true});
console.log(replacedTeam);
res.status(200).json({ message: 'Team was successfully overwritten!' });
} catch (err) {
console.log(err);
res.status(500).json({ message: 'An error occurred while updating the team.' });
}
};
I'm stuck in a function I'm working with ( I can be doing this all wrong ). So a quick explanation, I want to add bulk data in a collection, the collection is called "Sites" the format of the CSV is site,country,type. I'm trying to use promises for this (Bluebird). So consider the code:
Promise.each(sites, sites => new Promise((resolve, reject) => {
//console.log(sites);
let name = tools.extractDomain(req, res, sites[0]);
let country = sites[1];
let group = sites[2];
if (name != "" && country != "" && group != "") {
Site.findOne({ name: name }, "_id", function(err, duplicate) {
if (false) {
console.log("Duplicate site: " + duplicate);
} else {
//console.log("Adding " + name)
let site = new Site()
site.name = name
site.meta = {}
site.group = group
site.country = country
site.geomix = []
site.addedBy = req.user._id
site.addedAt = Date.now()
site.saveAsync().then(function(response){
tools.saveHistory(req, res, response._id, response.name, "Website Meta fetched.");
tools.saveHistory(req, res, response._id, response.name, "Link added for the first time."); //Save in history
resolve(site);
}).catch(function (e){
console.log(name);
reject();
});
}
});
}else{
console.log('Wrong Format');
}
}).then((data) => {
console.log('All websites processed!');
addedSites.push(data);
}).catch(err => {
//console.error('Failed');
}));
res.send({ status: 'ok', message: ''});
I'm making ajax calls so I return a res.send({ status: 'ok', message: ''}), I know that its in the incorrect place and I want to send some data along the res.send. Currently it sends the headers before the code actually finishes. I want to send the headers after all the data is added in Mongo but for every each in this case he resolve() so if I send the headers inside the ".then" of the ".each" I will get headers already sent error.
This might be a bit confusing. I feel I'm not doing this right. I'm going a bit crazy as well as I can't find a proper example that I can understand and implement.
But in the end my main question is: using an Ajax call what's the proper way to add let's say 1000 records in a collection using promises and actually control properly those who fail to add and those who don't?
Right now my code actually works but the logic is wrong for sure.
Thanks.
You can use bulkWrite on your model.
Ref: http://mongoosejs.com/docs/api.html#model_Model.bulkWrite
EDIT:
Sorry I misunderstood you. You need to move res.send({ status: 'ok', message: ''}); to then() and catch() blocks, so you will get something like this:
Promise.each(sites, sites => new Promise((resolve, reject) => {
// stuff you did before
}).then((data) => {
console.log('All websites processed!');
addedSites.push(data);
res.send({ status: 'ok', message: ''});
}).catch(err => {
res.send({ status: 'failed', message: err.message});
}));
This is what I came too, if someone can tell me if this is a good arch.
exports.addBulkSite = function(req, res, next) {
let siteArray = csv.parse((req.body.sites).trim()),
addedSites = [],
failedSites = [],
duplicated = [],
sites = siteArray,
size = sites.length,
processed = 0,
meta;
Promise.each(sites, sites => new Promise((resolve, reject) => {
let name = tools.extractDomain(req, res, sites[0]),
country = sites[1],
group = sites[2];
if (name != "" && country != "" && group != "") {
Site.findOneAsync({ name: name }, "_id").then(function(duplicate) {
duplicated.push(duplicate);
reject({name:name, message: 'Duplicated', critical:false});
}).catch(function(notDuplicated){
let site = new Site()
site = {
name: name,
meta: {},
group: group,
country: country, geomix:{},
addedBy: req.user._id,
addedAt:Date.now()
}
site.saveAsync().then(function(response){
tools.saveHistory(req, res, response._id, response.name, "Website Meta fetched.");
tools.saveHistory(req, res, response._id, response.name, "Link added for the first time."); //Save in history
resolve(site);
}).catch(function (e){
console.log(e);
reject({name:name, message: 'Error saving in the database. Please contact the administrator.', critical: true});
});
});
}else{
reject({name:name, message: 'Paramaters are missing', critical:false});
}
}).then((data) => {
processed++;
addedSites.push(data);
if(processed==size){
console.log('out');
res.send({ status: 'ok', addedSites: addedSites, failedSites: failedSites, duplicated: duplicated});
}
}).catch((err) => {
processed++;
console.log(err);
failedSites.push(err);
if(processed==size){
console.log('out');
res.send({ status: 'ok', addedSites: addedSites, failedSites: failedSites, duplicated: duplicated});
}
}));
}
I have a NodeJS application which is using mongoosastic api for Elasticsearch. Now I need a way of adding a condition(isDeleted == false) to the specified query(query: req.query.q).
this is my code
exports.search = function (req, res) {
if (!req.query.q) return res.status(400).send('No Query Provided')
log.error(req.query.q)
User.search({query_string: {query: req.query.q}}, (err, results) => {
if (err) return handleError(res, err)
var ret = _.map(results.hits.hits, result => ({
userID: result._id,
_score: result._score,
name: result._source.name,
loc: result._source.loc,
info: result._source.info,
images: result._source.images
}))
return res.send(ret)
})
}
How can I do that?
You can use filtering to filter your data. Check the example of your plugin website. Following example is your answer also.
var geoQuery = {query_string: {query: req.query.q}};
var myFilter = {
term: {
isDeleted: true
}
};
User.search(geoQuery, {filter: myFilter}, function(err, res) { /* ... */ })
I want to create API that allow other app to insert(create) new data. But so far I tried, this not work with error message "User id is required", I know that happen because no login user found when insert new data. Is it possible to insert new data without login or any possible way to login from server side if using accounts-password's package or any possible way to make this work?
code on server
Picker.route('/createFood/:title', function(params, req, res, next) {
console.log('-> params : ',params);
let username = (new Date()).getTime().toString();
function createFood() {
Fiber(function() {
console.log("-> username : ",username);
let acc = Accounts.createUser({
username: username,
email: username +'#foodie.com',
password: username
});
if (acc) {
console.log("-> acc : ",acc);
// Meteor.call("setUserId", acc);
Menus.insert({
title: params.title,
}, function(err, foodId) {
console.log("-> abs : ",Meteor.absoluteUrl());
console.log("-> err : ",err.message);
console.log("-> foodId : ",foodId);
let code, result;
if (err) {
code = 500;
result = {
error: err.message
}
} else {
code = 200;
result = {
foodId: foodId,
}
}
res.setHeader( 'Content-Type', 'application/json' );
res.statusCode = code;
res.end( JSON.stringify( result ) );
})
}
}).run();
}
if (params.title)
createFood();
});
code food model, there is userId owner here
if (Meteor.isServer) {
Menus.allow({
insert: function() {
return true;
},
update: function() {
return true;
},
remove: function() {
return true;
},
fetch: ['foodId'],
});
Menus.after.insert((userId, doc) => {
....
})
}
There is no reason why you can't insert to the database without logging in. You don't even have to include the accounts package if you don't want to .
Your current code doesn't insert unless a user is present, you can simplify it to this...
function createFood() {
Menus.insert({
title: params.title,