Why the data is being stored twice using mongoose? - javascript

I want to save a number of data in a property call cases. What I did was to iterate a list of data that I want to store, and then adding each data to the document's property. But the problem is that each data is being stored twice. I found a person in github who had the same issue, he said the problem was with nodemon, but I ran the sever again without nodemon and is the same problem.
Also found a question in stack saying that when a callback is applied it results in saving it twice, also the case is diferent from mine:
Why does using mongoose callback result in saving data twice?
I tried removing the callback, but I still have the same problem. (I dont think that a callback might do that)
This is the code:
var UserSchema = Schema({
user: {type: String},
password: {type: String},
name: {type: String},
privilege: {type: String},
cases: {type: Array}
})
var user = db.model('User', UserSchema , "users");
app.post("/addCases", function(req, res){
user.find({user: req.body.user}, async function(err, doc) {
if(err) {
console.log(err);
} else {
for (const iterator of req.body.list) {
await user.updateOne({user: req.body.user},
{ $push: {cases: iterator}}, {useFindAndModify: false}, function(err, raw) {
if(err) {
console.log(err);
} else {
console.log(value + ' <----- Value');
}
});
}
}
});
});

I think your problem might be related to you not ending the request in your server's code. After doing the modifications in your db, you should send a response to your front-end, if not it might try to repeat the request and you would end up with your endpoint being called two times.
Try something like:
app.post("/addCases", function(req, res){
user.find({user: req.body.user}, async function(err, doc) {
if(err) {
console.log(err);
} else {
for (const iterator of req.body.list) {
await user.updateOne({user: req.body.user},
{ $push: {cases: iterator}}, {useFindAndModify: false}, function(err, raw) {
if(err) {
console.log(err);
} else {
console.log(value + ' <----- Value');
}
});
}
}
// New code
res.json({ ok: true });
});
});

Related

Mongoose Schema Not Defined when Route is included in different file

To clean up my code, I decided to put all of my schemas and routes into different files in my directory, and require them in my app.js. Each Schema corresponds to each route. For all but one of my routes, I have gotten this to work, but for one specific one, I cannot find out why I am getting it as undefined.
Here is the code I have in my app.js (the main file)
// Schemas
const Transaction = require ("./models/transaction");
User = require ("./models/user");
Ticket = require ("./models/ticket");
Job = require ("./models/job");
Client = require ("./models/client");
// Routes
require("./routes/users")(app);
require("./routes/tickets")(app);
require("./routes/clients")(app);
require("./routes/jobs")(app);
require("./routes/transactions")(app);
All of these work, except for my transaction route.
Here is its schema:
// =======================Transaction Schema "./models/transaction"
var transactionSchema = new mongoose.Schema({
job: String,
client: String,
deposited_by_user: String,
transaction_info:{
amount: mongoose.Decimal128,
method: String,
receipt_number: String,
date: {type: Date}
},
billing_address: {
street: String,
city: String,
state: String,
zip: String
},
notes: String,
date_added: {type: Date, default: Date.now}
});
module.exports = mongoose.model("Transaction", transactionSchema);
And its route:
module.exports = function(app) {
// =======================Transaction "./routes/transactions"
// index
app.get("/transactions", function(req, res){
Transaction.find({}, function(err, transactions){ // It is at this line where it is telling me that "Transaction" is undefined. However, with this code pasted into the app.js exactly the same as it is here, it works fine.
if(err){
console.log("error")
} else {
for (let i = 0; i < transactions.length; i++){
transactions[i]["transaction_info"]["new_amount"] = numberWithCommas(transactions[i]["transaction_info"]["amount"]);
}
res.render("transactions", {transactions: transactions});
}
});
});
// new
app.get("/transactions/add", async function(req, res){
let endCollections = [];
for (let i = 0; i < collections.length; i++){
await collections[i].find({}, function(err, foundCollection){
if (err) {
console.log(err);
} else {
endCollections[i] = foundCollection;
}
});
}
res.render("add_transaction", {users: endCollections[0], clients: endCollections[2], jobs: endCollections[3]});
});
// show
app.get("/transactions/:id", function(req, res){
Transaction.findById(req.params.id, function(err, foundTransaction){
if (err){
console.log(err);
} else {
// Redirect
let price = numberWithCommas(foundTransaction["transaction_info"]["amount"]);
res.render("transaction", {transaction: foundTransaction, price: price});
}
});
});
// edit
app.get("/transactions/:id/edit", function(req, res){
Transaction.findById(req.params.id, async function(err, foundTransaction){
if (err){
console.log("error")
} else {
let endCollections = [];
for (let i = 0; i < collections.length; i++){
await collections[i].find({}, function(err, foundCollection){
if (err) {
console.log(err);
} else {
endCollections[i] = foundCollection;
}
});
}
let deposit_date = foundTransaction["transaction_info"]["date"];
deposit_date = moment(deposit_date).format("MM-DD-YYYY");
res.render("edit_transaction", {transaction: foundTransaction, users: endCollections[0], clients: endCollections[2], jobs: endCollections[3], deposit_date: deposit_date});
}
});
});
// create
app.post("/transactions", function(req, res){
// Create Transaction
Transaction.create(req.body.transaction, function(err, newTransaction){
if (err){
console.log(err)
} else {
// Redirect
res.redirect("/transactions");
}
});
});
// update
app.put("/transactions/:id", function(req, res){
// Update transaction
Transaction.findByIdAndUpdate(req.params.id, req.body.transaction, function(err, updatedTransaction){
if (err){
console.log(err)
} else {
// Redirect
res.redirect("/transactions/" + req.params.id);
}
});
});
// delete
app.delete("/transactions/:id", function(req, res){
// Delete job
Job.findByIdAndRemove(req.params.id, function(err, deletedTransaction){
if (err){
console.log(err)
} else {
// Redirect
res.redirect("/transactions");
}
});
});
}
I do not believe the Schema is the problem because when I paste the Transaction route code directly into my app.js file, character for character, it works fine. However, with it split (and the code stays exactly the same in the transactions.js file) I am getting the error when I load the page that "Transaction is undefined" at the part of my code that starts with Transaction.find
Overall, I cannot understand why when the route is in the app.js file, it works just fine, but when it is in a separate file, the Transaction variable is considered undefined; this is all despite it being modeled exactely the same as my other routes and schemas. Is there something here I am not seeing? Thanks.
1)
Instead of:
app.get("/transactions", function(req, res){
.
.
app.get("/transactions/:id", function(req, res){
Maybe just:
app.get("/", function(req, res){
.
.
app.get("/:id", function(req, res){
and so on?
2)
Transaction.find({}, function(err, transactions){
Instead of {} try ()
Transaction.find((), function(err, transactions){
It looks as you are passing one empty object

Node.js and mongoose update parameters

task.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var taskSchema = new Schema({
status: {type: String, default: 'TO-DO'},
contents: String,
createDate: {type: Date, default: Date.now},
author: {type:String, defafult:'Chris'}
});
module.exports = mongoose.model('Task', taskSchema);
task-controller.js
var Task = require('../models/task.js');
exports.update = function(req, res) {
Task.update({
contents : req.body.contents
}, {
status : req.body.status
}, function(err, numberAffected, raw) {
if (err) {
throw err;
}
console.log('The number of updated documents was %d', numberAffected);
console.log('The raw reponse from MongoDB was', raw);
});
res.redirect('/');
res.end();
};
At task-controller.js, You can see "numberAffected" and "raw" parameters.
However when I execute the code, the console displays
The number of updated documents was NaN
The raw reponse from MongoDB was undefined
So I searched the reference, but I can't find those kinds of parameters.
Are those parameters valid?
That is because Model.update returns a callback with only two parameters first parameter being err and second numAffected (which is Object not a number) as follows :
var Task = require('../models/task.js');
exports.update = function(req, res) {
Task.update({
contents : req.body.contents
}, {
status : req.body.status
}, function(err, numberAffected) {
//numberAffected is Object
if (err) {
throw err;
}
console.log('The number of updated documents was ', numberAffected); //Remove %d as numberAffected is not a number
});
res.redirect('/');
res.end();
};

Mongoose populate - Node.JS creating multiple objects

Task I have is to make a array of i.e. dishes that logged user is selecting as his favourite. Problem is that instead of one array of objectIDs i.e. dishes:[123456,5678910], i get two separate objects for same user with only one dish id in the array.
I presume that problem is in my schema, so can someone give me an idea?
var favoriteSchema = new Schema({
timestamps: true,
dishes: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Dish'
}],
postedBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
});
Edit>> My post method as demanded
.post(Verify.verifyOrdinaryUser, function (req, res, next) {
Favorites.create(req.body, function (err, favorite) {
if (err) throw err;
console.log('favorite created!');
var id = favorite._id;
favorite.postedBy = req.decoded._doc._id;
favorite.dishes.push(req.body);
favorite.save(function (err, favorite) {
if (err) throw err;
console.log('Updated Favorites!');
res.json(favorite);
});
});
Your post method is fine for the first time you want to add a favorite dish. The next time you add a dish for the same user you should call
Favorites.findOne({postedBy: req.decoded._doc._id}, function (err, favorite) {
favorite.dishes.push(req.body);
favorite.save(function (err, favorite) {
if (err) throw err;
res.json(favorite);
});
})

Node access multiple databases

I want to connect to different databases on server side so I can perform queries that include those two databases using node.
I have a config.js like this:
module.exports = {
database: {
user: 'brunojs',
password: 'bdpf5',
connectString: 'localhost:1521/orcl'
},
jwtSecretKey: "jmvhDdDBMvqb=M#6h&QVA7x"
};
This saves my info for accessing the first database.
Then I have one list.js file which performs the query:
var oracledb = require('oracledb');
var jwt = require('jsonwebtoken');
var config = require(__dirname + '../../config.js');
function get(req, res, next) {
oracledb.getConnection(
config.database,
function(err, connection){
if (err) {
return next(err);
}
connection.execute(
'select num_sequencial, notes, des_especialidade, dt_diag ' +
'from organite_repository ',
{},//no binds
{
outFormat: oracledb.OBJECT
},
function(err, results){
if (err) {
connection.release(function(err) {
if (err) {
console.error(err.message);
}
});
return next(err);
}
res.status(200).json(results.rows);
connection.release(function(err) {
if (err) {
console.error(err.message);
}
});
}
);
}
);
}
module.exports.get = get;
Everything works fine.
The thing is, right now, I want to perform queries using another database. How can I do that?
the right solution is to use pool https://github.com/oracle/node-oracledb/blob/master/doc/api.md#createpool
Creating massive pool:
module.exports = {
database: [{user: 'brunojs',
password: 'bdpf5',
connectString: 'localhost:1521/orcl',
poolAlias:'database1'
},
{user: 'brunojs',
password: 'bdpf5',
connectString: 'localhost2:1521/orcl',
poolAlias:'database2'
}],
jwtSecretKey: "jmvhDdDBMvqb=M#6h&QVA7x"
};
during initialization web-server, initialize the pools
const dbConfig = require('../config/database.js');
async function initialize() {
dbConfig.database.forEach(async function(item) {
const pool = await oracledb.createPool(item);
});
}
Then you can use the created pools when calling the connection procedure:
conn = await oracledb.getConnection('database1');
const execresult = await conn.execute(context.execsql, execbinds, context.opts);
First, add a second credentials object in your config.js
module.exports = {
database: {
user: 'brunojs',
password: 'bdpf5',
connectString: 'localhost:1521/orcl'
},
database2: {
user: 'user2',
password: 'password',
connectString: 'someotherhost:1521/orcl'
},
jwtSecretKey: "jmvhDdDBMvqb=M#6h&QVA7x"
};
then use one or other here:
oracledb.getConnection(
config.database, // you could change this line to config.database2
function(err, connection){
if (err) { ...
If you want to query one database, then another, you'd need to keep references to both connection objects (error checking omitted for brevity):
oracledb.GetConnection(
config.database,
function(err, connection1) {
oracledb.GetConnection(
config.database2,
function(err, connection2) {
// in this function you can use either connection object
connection1.execute(...);
connection2.execute(...);
}
});
This is slightly out of scope for your question, but you could also take a look at Waterline. It supports setting up multiple databases and then tying models to them, so that knowing where certain data models are stored is abstracted away.
you can always use links on the DB side, so your java code does not have to connect to another DB, for example:
select num_sequencial, notes, des_especialidade, dt_diag
from organite_repository#linkA
UNION
select num_sequencial, notes, des_especialidade, dt_diag
from organite_repository#linkB
/* ... */

Bypass mongoose getter

I was trying to use mongoose getter to cast all user password before send out. It works perfectly.
However, on method "comparePassword", I need the passwordstring to compare sothen I can authenticate.
Is there a way to bypass the getter under certain conditions in mongoose? Thanks in advance!
Code Example:
function castpassword (pw) {
return 'keyboard cat';
}
var AccountSchema = new Schema({
password: { type: String, get: castpassword }
});
AccountSchema.methods.comparePassword = function (candidatePassword, cb) {
// random hash vs keyborad cat === not authenticated
crypt.compare(candidatePassword, this.password, function (err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
....
Account.findById( someId, function (err, found) {
console.log(found.password); // 'keyboard cat'
});
You can use mongoose 'lean' to skip all mongoose magic and just pull out a json object.
Account
.findById(someId)
.lean()
.exec(function (err, found) {
console.log(found.password); // actual password
// you can not use mongoose functions here ex:
// found.save() will fail
})
Another option would be to set password to 'select: false' in the schema.
var AccountSchema = new Schema({
password: { type: String, select: false }
});
This way anytime you pull out the document the password field would not be there at all unless you specifically as for it.
Account
.findById(someId, function (err, found) {
console.log(found.password); // undefinded
})
Account
.findById(someId)
.select('password') // explicitly asking for password
.exec(function (err, found) {
console.log(found.password); // actual password
})
Using this.toObject() in mongoose will bypass all getter and setter settings in mongoose since it change it to plain JSON data
AccountSchema.methods.comparePassword = function (candidatePassword, cb) {
// keyboard cat vs keyboard cat === authenticated
crypt.compare(candidatePassword, this.toObject().password, function (err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};

Categories