Reputation: 11797
I'm using mongoose with node, I have some functionality that allows the user to upload a CSV the data is then put into mongo.
I am trying to prevent duplicate usernames from being uploaded. To mitigate this I have call findOne and look for the username before saving the entry to the db, if it finds the username it should call async's callback()
and moves onto the next iteration.
I have a save callback that I expect only to be called when the data is in the database, in this callback I call callback()
.
From my console logs each duplicate findOne comes up as null, but the data is in fact being written to the database (if I try upload more duplicates in a csv afterwards everything works as expected).
It's almost as if the save callback is being called just before the db write actually occurs and so the next call does not find the duplicate, do I have some fundamental misunderstanding of how mongo writes to the db or am I overlooking something obvious...
admin.post('/upload', function(req, res) {
if(req.files.file) {
var file = req.files.file;
fs.readFile(file.path, 'utf8', function(err, data) {
if(err) return res.json({error: err});
csv.parse(data, function(err, parsed) {
// remove header
if(!parsed) {
return;
}
parsed.splice(0, 1);
var headers = ['auth', 'sid', 'fl', 'dd'];
async.each(parsed, function(row, callback) {
var seed = {};
for(var i = 0; i < 4; i++) {
if(row[i] && row[i].trim() !== '') {
seed[headers[i]] = row[i].trim();
}
}
if(seed.user && seed.password) {
User.findOne({username: seed.user}, function(err, result) {
if(err) {
console.log(err);
return res.json({error: err});
}
console.log(result);
if(!result) {
console.log('creating user');
var user = new User({
username: seed.user,
password: User.generateHash(seed.password),
});
user.save(function(err) {
if(err){
return res.json({error: err});
}
console.log('SAVED CALLING CB');
callback();
});
} else {
callback();
}
});
} else {
callback();
}
}, function() {
return res.json({success: true});
});
});
});
}
});
Upvotes: 0
Views: 121
Reputation: 14562
You are probably running into a race condition in there, and this appear to be the case since you said that your script works on a second run.
Because async.each
runs in parallel, if the duplicate usernames are in lines next to each other in the CSV file it is possible that two findOne
calls are made before the first save
is.
I would recommend that you enforce the uniqueness on the database, using an unique index. It would also be more performatic (you only hit the database once per user) and you'll only have to handle the unique constraint error instead.
Upvotes: 3