Why is forEach statement running more times than expect - mongodb

I have the following function which is not working as expected for example I would like to create 24-irds and 3-smallparts, but instead I'm getting 24-irds and 72-smallparts. It seems like the smallparts forEach is iterrating the number of irds instead of smallparts. Any ideas why?
Thanks in advance
exports.pickup = function (req, res) {
async.waterfall([
function (callback) {
var order = createOrder(req);
callback(null, order);
},
function (order, callback) {
if (req.body.irds.length > 0) {
_(req.body.irds).forEach(function (n) {
var receiver = new Receiver(n);
receiver.order = order._id;
receiver.company = req.user.company;
receiver.user = req.user;
receiver.date = req.body.date;
receiver.location = req.user.location;
order.receivers.push(receiver._id);
receiver.save(function (err) {
callback(null, order);
if (err) {
console.log('error receiver exists');
}
});
});
} else {
callback(null, order);
}
},
function (order, callback) {
if (req.body.smallParts.length > 0) {
_(req.body.smallParts).forEach(function (n) {
var now = new Date();
var query1 = {'_id': req.user.company, 'products.product': n.product};
var query2 = {'_id': req.user.company};
var update1 = {
$inc: {
'products.$.quantity': n.quantityRequested,
'products.$.quantityOnhand': n.quantityRequested
},
'products.$.updated': now,
'products.$.lastPickUp.date': now,
'products.$.lastPickUp.quantity': n.quantityRequested
};
var update2 = {
$push: {
'products': {
'product': n.product,
'quantity': n.quantityRequested,
'quantityOnhand': n.quantityRequested,
'updated': now,
'lastPickUp.date': now,
'lastPickUp.quantity': n.quantityRequested
}
}
};
var options = {upsert: true};
Companies.findOneAndUpdate(query1, update1, function (err, doc) {
if (!doc) {
Companies.findOneAndUpdate(query2, update2, function (err, doc) {
if (err) {
throw err;
}
});
}
});
//save smallparts
n._id = new ObjectId();
var smallPart = new SmallPart(n);
smallPart.order = order._id;
smallPart.quantity = n.quantityRequested;
smallPart.company = req.user.company;
smallPart.user = req.user;
smallPart.location = req.user.location;
smallPart.date = req.body.date;
order.smallParts.push(smallPart._id);
smallPart.save(function (err) {
callback(null, order);
if (err) {
console.log(err);
}
});
})
} else {
callback(null, order)
}
},
function (order, callback) {
order.location = req.user.location;
order.company = req.user.company;
order.save(function (err) {
callback(null, 'done');
if (err) {
console.log(err);
}
});
}
], function (err) {
if (!err) {
res.status(200).json();
} else {
console.log(err);
}
});
};

I managed to figure out.
exports.pickup = function (req, res) {
var order = createOrder(req);
order.location = req.user.location;
order.company = req.user.company;
order.type = 'pickup';
async.series([
function (callback) {
if (req.body.irds.length > 0) {
_(req.body.irds).forEach(function (n) {
var receiver = new Receiver(n);
receiver.order = order._id;
receiver.company = req.user.company;
receiver.user = req.user;
receiver.date = req.body.date;
receiver.location = req.user.location;
order.receivers.push(receiver._id);
receiver.save(function (err) {
if (err) {
console.log('error saving receiver');
}
});
});
}
callback(null);
},
function (callback) {
if (req.body.smallParts.length > 0) {
_(req.body.smallParts).forEach(function (n) {
var now = new Date();
var query1 = {'_id': req.user.company, 'products.product': n.product};
var query2 = {'_id': req.user.company};
var update1 = {
$inc: {
'products.$.quantity': n.quantityRequested,
'products.$.quantityOnhand': n.quantityRequested
},
'products.$.updated': now,
'products.$.lastPickUp.date': now,
'products.$.lastPickUp.quantity': n.quantityRequested
};
var update2 = {
$push: {
'products': {
'product': n.product,
'quantity': n.quantityRequested,
'quantityOnhand': n.quantityRequested,
'updated': now,
'lastPickUp.date': now,
'lastPickUp.quantity': n.quantityRequested
}
}
};
var options = {upsert: true};
Companies.findOneAndUpdate(query1, update1, function (err, doc) {
if (!doc) {
Companies.findOneAndUpdate(query2, update2, function (err, doc) {
if (err) {
throw err;
}
});
}
});
//save smallparts
n._id = new ObjectId();
var smallPart = new SmallPart(n);
smallPart.order = order._id;
smallPart.quantity = n.quantityRequested;
smallPart.company = req.user.company;
smallPart.user = req.user;
smallPart.location = req.user.location;
smallPart.date = req.body.date;
order.smallParts.push(smallPart._id);
smallPart.save(function (err) {
// callback(null, order);
if (err) {
console.log(err);
}
});
})
}
callback(null, order)
}
],
function (err) {
if (!err) {
order.save(function (err) {
if (!err) {
res.status(200).json();
} else {
console.log('error saving order')
}
});
} else {
console.log(err);
}
});
};

Related

findByIdAndUpdate do not update document

I am trying to update a field to the document with findByIdAndUpdate. The field I am trying to update is defined in the Bar Model. And I can also assure that req.body.bookId has a valid id.
Here's how my request looks,
app.patch("/foo", async (req, res) => {
try {
await validateId(req.body.bookId);
let doc = await Bar.findByIdAndUpdate(
req.body.bookId,
{ DateT: Date.now() },
{ new: true }
);
res.send(doc);
} catch (err) {
console.log(err);
}
});
Bar schema,
const mongoose = require("mongoose");
const barSchema = mongoose.Schema({
bookId: {
type: String,
unique: true,
},
DateT: {
type: Date,
default: null,
},
});
module.exports = mongoose.model("Bar", barSchema);
use updateOne, when you use async don't use .then() use try/catch
test it:
app.patch("/foo", async (req, res) => {
try {
let doc = await Bar.updateOne(
{ bookId : req.body.bookId },
{ DateT: Date.now() },
{ new: true }
);
res.send(doc);
} catch (error) {
console.log(error);
}
});
app.patch("/foo", async (req, res) => {
await Bar.findByIdAndUpdate(
req.body.bookId,
{ DateT: Date.now()},
(err, docs) => {
if (err) {
console.log(err);
} else {
res.send(docs);
}
}
);
});

How to make auto suggestion in mean stack

I have this code :
async function getUserByArtistName(artistName) {
let userDB = await User.find(
{$text: { $search: artistName}},
(err, res) => {
if(err){
console.log("ERROR : ")
console.log(err)
} else {
console.log(res)
}
});
return userDB;
}
and i need to find user where User.artistName contains * artistName *. is it possible ?
Thank you verry much !
the answer :
async function getUserByArtistName(artistName) {
let userDB = await User.find(
{ artistName: { $regex: artistName, $options: "i" } },
(err, res) => {
if(err){
console.log("ERROR : ")
console.log(err)
} else {
console.log(res)
}
});
return userDB;
}

Mongoose update only the values that have changed

I have a PUT route to update value. I am hitting this route from two places. One is sending information about details and one about completed. The problem is that mongoose is updating booth even though it gets value from only one.
So if I send information about completed that it is true and latter I hit this route with new details (that dont have completed value) it will update completed also to false. How do I update just the value that was changed?
router.put('/:id', (req, res) => {
Todo.findOne({_id:req.body.id}, (err, foundObject) => {
foundObject.details = req.body.details
foundObject.completed = req.body.completed
foundObject.save((e, updatedTodo) => {
if(err) {
res.status(400).send(e)
} else {
res.send(updatedTodo)
}
})
})
})
EDIT:
Thanks to Jackson hint I was managed to do it like this.
router.put('/:id', (req, res) => {
Todo.findOne({_id:req.body.id}, (err, foundObject) => {
if(req.body.details !== undefined) {
foundObject.details = req.body.details
}
if(req.body.completed !== undefined) {
foundObject.completed = req.body.completed
}
foundObject.save((e, updatedTodo) => {
if(err) {
res.status(400).send(e)
} else {
res.send(updatedTodo)
}
})
})
})
const updateQuery = {};
if (req.body.details) {
updateQuery.details = req.body.details
}
if (req.body.completed) {
updateQuery.completed = req.body.completed
}
//or
Todo.findOneAndUpdate({id: req.body.id}, updateQuery, {new: true}, (err, res) => {
if (err) {
} else {
}
})
//or
Todo.findOneAndUpdate({id: req.body.id}, {$set: updateQuery}, {new: true}, (err, res) => {
if (err) {
} else {
}
})
Had a function similar to this my approach was this
const _ = require('lodash');
router.put('/update/:id',(req,res, next)=>{
todo.findById({
_id: req.params.id
}).then(user => {
const obj = {
new: true
}
user = _.extend(user, obj);
user.save((error, result) => {
if (error) {
console.log("Status not Changed")
} else {
res.redirect('/')
}
})
}).catch(error => {
res.status(500);
})
};
Taking new : true as the value you updating
It gets kinda ugly as the fields to be updated get increased. Say 100 fields.
I would suggest using the following approach:
try {
const schemaProperties = Object.keys(Todo.schema.paths)
const requestKeys = Object.keys(req.body)
const requestValues = Object.values(req.body)
const updateQuery = {}
// constructing dynamic query
for (let i = 0; i < requestKeys.length; i++) {
// Only update valid fields according to Todo Schema
if ( schemaProperties.includes(requestKeys[i]) ){
updateQuery[requestKeys[i]] = requestValues[i]
}
}
const updatedObject = await TOdo.updateOne(
{ _id:req.params.idd},
{ $set: updateQuery }
);
res.json(updatedObject)
} catch (error) {
res.status(400).send({ message: error });
}

mongoose can't save data

I meet some trouble need your help ~~ thx
I am use mongoose + superAgent + feedparser + eventProxy to get Rss and save these datas
now I can get and finish parse these dataes however I can't save them with moogose
I have 3 module are dao.js , app.js and service.js
I configure dao as this codes
var mongoose = require("mongoose"),
db,
modelName = "news"; // 设定操作的collections
mongoose.connect("mongodb://localhost:27017/test");
db = mongoose.connection;
db
.on("error", function (err) {
console.log("Connection Error!!! this's some prompts: ");
console.log(err);
})
.once("open", function () {
console.log("Open DataBase Successfully!!!");
});
// 设置
var newsSchema = mongoose.Schema({
"category": String,
"data": [{
"title": String,
"link": String,
"pubDate": String,
"source": String,
"author": String
}]
});
console.log(newsSchema.ObjectId);
newsSchema.pre("save", function (next) {
if( !this.title ) {
this.title = "未知标题";
}
next();
})
var newsModel = mongoose.model(modelName, newsSchema);
module.exports = {
model: newsModel,
schema: newsSchema,
mongoose,
db
}
and save data as these codes:
saveData(callback) {
var $self = this;
for(var i = 0; i<$self.result.length; i++) {
new model($self.result[i]).save(function (err) {
if(err) {
console.log(err)
} else {
console.log("数据存储成功!")
}
});
}
callback && callback();
db.close();
}
Now the data can't save successfully meanwhile the save callback func don't run
Could you give me some advise?

MEAN: Getting total value from mongodb

Im new to mean stack and Im using mongoskin to connect to mongodb..Im trying to get total value present in database
function getTotal() {
var deferred = Q.defer();
var dashboard = db.collection('dashboard');
db.collection('dashboard').find({"iscorrect" : ""}).count(),
function (err, doc) {
if (err){
deferred.reject(err);
} else{
deferred.resolve();
}
};
return deferred.promise;
}
my main controller has
function gettotal(req, res) {
userService.getTotal()
.then(function () {
res.sendStatus(200);
})
.catch(function (err) {
res.status(400).send(err);
});
}
The following code does not return any value...Any help in getting total value is helpful
Because count() method is asynchronous and returns a promise, you can restructure your function as either using a callback function
function getTotal() {
var deferred = Q.defer();
db.collection('dashboard').count({"iscorrect" : ""}, function (err, result) {
if (err){
deferred.reject(err);
} else{
deferred.resolve(result);
}
});
return deferred.promise;
}
or since count() returns a Promise, just return it
function getTotal() {
// just return a Promise
return db.collection('dashboard').count({"iscorrect" : ""});
}
and in your controller:
function gettotal(req, res) {
userService.getTotal()
.then(function (count) {
res.status(200).json({ 'count': count });
})
.catch(function (err) {
res.status(400).send(err);
});
}