NodeJS bulk remove mongodb documents - javascript

I have a collection with some bad data. I would like to bulk delete this data based on some query. This is easy in the mongo shell as db.collection.remove() allows you to specify the justOne option. Is there some way to do this in the node.js driver? findAndRemove seems to only delete 1 document and has no option to make it bulk?
db.collection(collection_name, function(err, collection){
collection.findAndRemove({type: 'LUXURY'}, function(err, result){
// result is only a single document
console.log(result._id.toString());
});
});
I know an alternative to this is to find() all documents that satisfy my query and manually create a BulkOp using initializeUnorderedBulkOp and populate it by iterating over the results of my find, but I feel there should be an easier way.

If you are using node-mongo-native driver, I can't see any reason why you don't use the remove directly.
db.collection(collection_name, function(err, collection){
collection.remove({type: 'LUXURY'}, function(err, result){
// your code here.
});
});

Related

Model.findOneAndRemove (MongoDB & Mongoose) specificity?

I've been trying to build my first solo CRUD app (without following a tutorial) and came across something a little weird which I can't wrap my head around. Apologies if it's rather obvious, but I couldn't find anything on here about it.
I added my delete route for one of my models and used the following code:
// delete list
router.delete("/lists/:id", function(req, res){
// find list by ID and remove it
List.findOneAndRemove(req.params.id, function(err, deletedList){
if(err) {
console.log("ERROR DELETING LIST");
console.log(err);
res.redirect("/lists");
} else {
// if list is removed successfully, remove each item
console.log(deletedList);
Item.remove({_id: {$in: deletedList.items}}, function(err, deletedItems){
if(err) {
console.log("ERROR DELETING ITEMS");
console.log(err);
} else {
console.log("SUCCESSFULLY DELETED LIST & ALL ITEMS");
res.redirect("/lists");
}
});
}
});
});
Now, it deletes things from the database, however it doesn't delete the right thing. I have a button on my web page which submits a form. The form's action is generated based on the page content where I insert the ID of the model into the action using EJS. When I submit the form to delete the model and it's referenced items, it ends up deleting the first document in the database, even though (to my understanding), I've specified that only documents which match the provided ID should be deleted.
I did fix it, by replacing
List.findOneAndRemove(req.params.id, function(err, deletedList){
if(err) {
console.log("ERROR DELETING LIST");
console.log(err);
res.redirect("/lists");
} else {
with
List.findOneAndRemove({_id: {$in: req.params.id}}, function(err, deletedList){
if(err) {
console.log("ERROR DELETING LIST");
console.log(err);
res.redirect("/lists");
} else {
though I'm not completely sure on why this works and req.params.id doesn't. I was just hoping for some clarification in case I come across something similar in the future.
I believe it is deleting the first item in your array because you are using "FindOneAndRemove" - as is suggested in the name, this will limit the match to a single document. And in your first version of the code:
List.findOneAndRemove(req.params.id, function(err, deletedList){
You aren't specifying your _id field, so i believe it is matching everything, and is only removing a single document due to the method you are using. Where as in the second one, you are
List.findOneAndRemove({_id: {$in: req.params.id}}, function(err, deletedList){
Here's a possible reason I can point. When you pass req.params.id to findOneAndRemove, since JS is not a strongly typed language and you are not specifically typing it, Mongoose isn't sure about what to delete.
The first parameter to findOneAndRemove is the filter object and Mongoose is not able to find the right filtering since the data type that is passed here is a string.
I think then Mongoose consider an empty filter and as usual, empty filter deletes the first item.
One try you can do is to explicitly type the _id, say like
var id = new mongoose.mongo.ObjectID(req.params.id)
and pass this id to the findOneAndRemove() function.
Hope this helps.

Pushing String into database utilizing nodeJS and mongoDB

I am new to JS and I am utilizing the MEAN stack to create a place where students can add classes to their user profile. I already have a session store in my database, so "req.user" will return the currently logged in user information and specifically "req.user.id" will return the currently logged in user's id. Also, I have figured out how to search a course in my database from my application. Ultimately, my goal is that when the user makes the post request to search in the database, I also want those "values" to be pushed into the classes "key". I have provided two options, both of which do not add the respective strings to the database. Thank you for any help!
Portion of Search.JS Option #1
router.post('/', ensureAuthenticated, function (req,res,next) {
var query = {course: req.body.coursename};
db.collection('courses').find(query).toArray()
.then(db.collection('DefaultUser').update({_id: req.user.id}, {$push: {classes: req.body.coursename}}));
res.render('search', {title: 'search'})
});
Portion of Search.JS Option #2
router.post('/', ensureAuthenticated, function(req,res,next) {
var query = {course: req.body.coursename};
db.collection('courses').find(query).toArray((err, results) => {
if (err) {
throw err;
} else {
db.collection('DefaultUser').updateOne({_id: '5c17161d3347e79410ff29ba'}, {
$push: {
classes: req.body.coursename
}
})
console.log(results)
res.render('search', {courses: results, title: 'search'})
}
})
});
Some tips may help:
req.body will hold nothing if you forget to use app.use(express.urlencoded()) to parse the posted data.
You may use ObjectId('<string>') (in option #2) for finding and updating queries, not just the string, because mongodb stores _id as ObjectId type by default.
You may use $addToSet instead of $push modifier to add a unique element to an array, or you may get one student subscribed with two more same class, if he repeatedly submit the form.
In your code, you find in the courses collection first and then update, but since you did nothing with the find result, it is not necessary (empty result does not throw any error). Checking the data is valid is good practice, if you would like to do so, in both options, you need to use findOne instead of find to make sure the course is existed, and .then(course => {/* check if the course is null and then throws an error */} ).
I don't have the full code of your project so I can only guess there may be the problems listed above, wish you good luck!

How to insert multiple documents at once in MongoDB while skipping documents with duplicate fields

I am using the native Node.js MongoDB driver to insert multiple documents at once. I have an array of javascript objects (where each object represents a user), and I am using the following code.
var col = db.collection('users');
col.insertMany(usersArray, function(err, r) {
if (err) {
log('Bulk Insert Error', err);
} else {
log('Successful Insert', r.insertedCount);
db.close();
}
});
Each user document in the usersArray array has an email field. I do not want to insert objects where a document with the email already exists in the users collection, as I have modelled emails to be unique. Such documents should be skipped in the query.
I know this would be achievable if usersArray had an _id field (where I would use continueOnError: true), but unfortunately my usersArray is from a separate source. Doing single inserts is inefficient, as my usersArray can have well over ~1000 objects.
The work around I have thought of is selecting all documents from db and reconstructing the usersArray with only unique documents in my node application, to reduce the number of requests to MongoDB. Is there a way the collection.insertMany() function can be modified to do this? Raw MongoDB queries will also be appreciated.

How to create users from array and return their ids in mongoose?

Service get array of users' names, check every name if user with this name exists(if not then create user) and return ids of users with such names. I don't know how to do it because search and save are async.
Following code is for query the collection to get a document based on id .if its found it returns the doc other wise it can inseret the doc for that we used {upsert:true}.this is basic code sample follow mongoose docs http://mongoosejs.com/docs/api.html
Model.findOneAndUpdate({_id:id},{upsert:true}, function(err, doc){
if (err) {
console.log('if error occurs');
} else {
console.log('doc',doc)
}
});
I did it using async library for node js.

Express.js collection.find() return Object

I am wanted to display every documents stored in my mongodb. I tried following code which simply get collection.find() and display through res.send()
router.get('/index', function(req,res){
var db = req.db
var collection = db.get('usercollection')
var display = util.inspect(collection.find()));
res.send(display);
});
I expected it to display the actual document stored in mongodb. But instead, it displayed this object format:
{cold:{manager:{driver:[Object], helper:[Object], collection:[Object].....
Is there any other steps needed to display raw mongodb document?
If the library you are using is the official 10gen library, then you can't simply output collection.find() without unwinding it. The easiest way to do that for smaller datasets is
collection.find().toArray(function(err, results) {
if (err) {
// do something error-y
} else {
res.send( results );
}
});
If you post more of your code, and tag your question with the libraries you are using, you'll be able to get more targeted help. If the library you are using returns a promise, this is probably how you'd unwind it:
collection.find().then(function(results){
res.send(results);
}).catch(function(err){
console.error(err);
});

Categories

Resources