nodejs/mongodb, remove entire collection - mongodb

I'm trying to remove all items in a collection.
db.collection('sessions', function(err, collection) {
collection.remove();
});
This is the error I get:
node.js:134
throw e; // process.nextTick error, or 'error' event on first tick
^
TypeError: Cannot call method 'getRequestId' of null
at [object Object].executeCommand (/srv/www/www.cidev.com/nodejs/node_modules/mongodb/lib/mongodb/db.js:778:48)
at Collection.remove (/srv/www/www.cidev.com/nodejs/node_modules/mongodb/lib/mongodb/collection.js:199:26)
at /srv/www/www.cidev.com/nodejs/session/memory/index.js:15:20
at [object Object].collection (/srv/www/www.cidev.com/nodejs/node_modules/mongodb/lib/mongodb/db.js:197:12)
at new <anonymous> (/srv/www/www.cidev.com/nodejs/session/memory/index.js:14:11)
at Object.<anonymous> (/srv/www/www.cidev.com/nodejs/session/memory/index.js:157:16)
at Module._compile (module.js:411:26)
at Object..js (module.js:417:10)
at Module.load (module.js:343:31)
at Function._load (module.js:302:12)
However, I can do this via mongodb fine:
db.sessions.remove();
What's the best way to achieve what I want via node?
Thanks

Going back to this... just to update the question.
store.collection('sessions',function(err, collection){
collection.remove({},function(err, removed){
});
});

I know this is a little late to the party and much has changed, but to remove a collection in node, you do this:
db.collection('someCollection').drop();
From the mongo terminal you do this:
db.someCollection.drop();
It's that simple.

Providing a more recent answer, based on API changes and trying the previous answers myself.
The following example represents a block of code as we use it in our integration tests:
const mongoUrl = 'mongodb://localhost:27017/test-database';
const mongoClient = await MongoClient.connect(mongoUrl, {
useNewUrlParser: true,
useUnifiedTopology: true
});
const database = mongoClient.db();
if (database) {
const collections = await database.listCollections();
await collections.forEach(async collection => {
console.log(`Dropping ${collection.name}`);
await database.collection(collection.name).drop();
});
}
Note, while you could use the following, it will fail if you don't have full permissions over the database, such as in Mongo Cloud:
await database.dropDatabase();
For context, I was using mongodb package 3.5.9 and node 14.15.1.

I'm not sure whether you were able to figure this out, but your code did not work for me...perhaps because of changes in the API? Anyway I was able to remove an entire collection's contents using the following code:
db.CollectionName.remove().exec(function(error) {
if(error) {
console.log('Uh oh: ' + error);
}
else {
console.log(' [Existing Collection Deleted]');
}
});

Related

Mongoose findOne() within a transaction : Uncaught TypeError: Cannot read property '$elemMatch' of undefined

I'm already many hours on this and I can't find a solution.
I'm using Node/Express and trying to run a Mongoose (^5.2.0) findOne with transactions. For the database, I'm running it in memory, with run-rs.
The collection is being previously populated with a valid document, which I can find using mongo shell:
rs:PRIMARY> db.lots.findOne("aaaabbbbccccdddd11112222")
{
"_id" : ObjectId("aaaabbbbccccdddd11112222"),
"availableQty" : 0,
"expirationDate" : ISODate("2019-01-10T15:10:29.455Z"),
"__v" : 0
}
But whenever I run this code below, I'm getting an error:
const save = async (lotId) => {
const session = await mongoose.startSession()
await session.startTransaction()
try {
let lot = await Lots.findOne(lotId, session)
console.log('result: ' + lot)
await session.commitTransaction()
await session.endSession()
return lot
} catch(err) {
console.error('caught error: ' + err)
await session.abortTransaction()
await session.endSession()
throw err
}
}
Error:
Uncaught TypeError: Cannot read property '$elemMatch' of undefined
at model.Query._castFields (node_modules/mongoose/lib/query.js:3873:22)
at model.Query.Query._findOne (node_modules/mongoose/lib/query.js:1861:23)
at process.nextTick (node_modules/kareem/index.js:333:33)
at _combinedTickCallback (internal/process/next_tick.js:95:7)
at process._tickCallback (internal/process/next_tick.js:161:9)
And it seems it's not even caught in the catch(), since my console.log is never printed.
Try to change
findOne(lotId, session)
to
findById(lotId).session(session)
Mongoose uses Node.js MongoDB driver that has slightly different syntax than native MongoDB. Method findOne accepts object not an id (see https://mongoosejs.com/docs/api.html#model_Model.findOne). So you can either use
findOne({ _id: lotId })
or simply
findById(lotId)
Both these methods return Query object, which has method session, that accepts session (see https://mongoosejs.com/docs/api.html#query_Query-session).
I recommend you to read documentation about transactions first to clarify other things: https://mongoosejs.com/docs/transactions.html
edit:
Also to use await with Mongoose, you need to use exec() at the end of the query, because Query object does not return Promise and only returns thenable (see https://mongoosejs.com/docs/promises.html).
So correct query should look like this
const lot = await Lots.findById(lotId).session(session).exec();
Hope it helps,
Tomas :)

Meteor-Mongo: Error handling for findone

I am trying to handle errors using findOne in meteor-mongo.
From this stackoverflow question, it appears that I should be able to handle errors by doing collection.findOne({query}, function(err, result){ <handleError> }, but doing so results in an errormessage:
"Match error: Failed Match.OneOf, Match.Maybe or Match.Optional validation"
The following code works:
export default createContainer((props) => {
let theID = props.params.theID;
Meteor.subscribe('thePubSub');
return {
x: theData.findOne({_id: theID}),
};
}, App);
The following code does not:
export default createContainer((props) => {
let theID = props.params.theID;
Meteor.subscribe('thePubSub');
return {
x: theData.findOne({_id: theID}, function(err,result){
if(!result){
return {}
};
}),
};
}, App);
What am I doing wrong and how should I be resolving this error? Is this a meteor specific error?
Any help is greatly appreciated!
What kind of error are you exactly trying to handle with your callback?
Meteor's findOne is different from node's mongodb driver's findOne that the post you link to uses.
The expected signature is:
collection.findOne([selector], [options])
There is no callback involved, since the method runs synchronously (but is reactive).
If you want to return a default value when the document is not found, you can simply use a JS logical OR:
// Provide an alternative value on the right that will be used
// if the left one is falsy.
theData.findOne({_id: theID}) || {};
A more rigorous approach would be to compare its type with
typeof queryResult === 'undefined'
Note that if theData collection is fed by the above subscription Meteor.subscribe('thePubSub'), I doubt Meteor will have time to populate the collection on the client by the time you query it…

In Meteor.js, use multiple MongoInternals.RemoteCollectionDriver with same collection name

MongoInternals.RemoteCollectionDriver("mongodb://#{server.ip}:#{server.port}/#{server.dbName}")
If I call multiple remote MongoDB methods and if there are collecitons with the same names, Meteor throws the error something like this, "collectionName/insert is already exist..."
I think Meteor creates each collection's methods internally so that control each collection, but I need to control several MongoDB at a time with some reasons.
How can I avoid this situation?
In addition,
I realize I can use Npm Mongo driver directly like this without any NPM package involving.
var MongoClient = MongoInternals.NpmModules.mongodb.module.MongoClient;
// Connection URL
var url = 'mongodb://localhost:27017/myproject';
// Use connect method to connect to the Server
MongoClient.connect(url, function(err, db) {
console.log("Connected correctly to server");
try {
var collection = db.collection('documents');
collection.find({}).toArray(function(err, docs){
console.log(err);
console.log(docs);
});
}
catch(err) {
console.log(err);
}
db.close();
});
But this still forces me to control each DB with the Node.js callback style.
Is there any idea to avoid this?
I have been checking this issue, and I found a way to do it.
The solutions that I had seen to connect several databases where:
storageServerDriver = new MongoInternals.RemoteCollectionDriver("mongodb://ip:port/dbName")
#Collection = new Mongo.Collection("collection", { _driver: storageServerDriver })
But as you mentioned before, with two collections with same name, an error was thrown (internally Meteor identifies the collections by their name, so it tries to override the structure of the collection already created).
Anyway, to fix this, you can use the following hack:
storageServerDriver = new MongoInternals.RemoteCollectionDriver("mongodb://ip:port/dbName")
#CollectionTwo = storageServerDriver.open('collection')

Meteor returning a field from MongoDB works in console but not in application

I am trying to read out a file in my MongoDB database. In the console the response is correct while in my application I get the following error:
Uncaught TypeError: Cannot read property 'iati' of undefined
I defined a template helper which should return a certain sub-field within my MongoDB collection. However the following does not seem to work (I get the beforementioned error).
Template.hello.helpers({
test: function() {
return Test.findOne().iati;
}
});
What does seem to work is to return the entire object:
Template.hello.helpers({
test: function() {
return Test.findOne();
}
});
And then call the specific field within the template:
{{test.iati}}
However, I want to use the data within the JavaScript script. What am I doing wrong?
Collection methods like Tests.findOne() return the documents that are already fetched to the client's Minimongo copy. Before your document is fetched, findOne() will return null.
To safeguard against this, simply check the result in the helper before you proceed with the calculation:
Template.hello.helpers({
test: function() {
if(! Test.findOne()) return;
return Test.findOne().iati;
},
});
You can also wait for the subscription in the Iron Router to ensure the proper documents are loaded:
this.route('routeName', {
...
onBeforeAction: function() {
this.subscribe('subscriptionName').wait();
...
},
...
});

Delete a key from a MongoDB document using Mongoose

I'm using the Mongoose Library for accessing MongoDB with node.js
Is there a way to remove a key from a document? i.e. not just set the value to null, but remove it?
User.findOne({}, function(err, user){
//correctly sets the key to null... but it's still present in the document
user.key_to_delete = null;
// doesn't seem to have any effect
delete user.key_to_delete;
user.save();
});
In early versions, you would have needed to drop down the node-mongodb-native driver. Each model has a collection object that contains all the methods that node-mongodb-native offers. So you can do the action in question by this:
User.collection.update({_id: user._id}, {$unset: {field: 1 }});
Since version 2.0 you can do:
User.update({_id: user._id}, {$unset: {field: 1 }}, callback);
And since version 2.4, if you have an instance of a model already you can do:
doc.field = undefined;
doc.save(callback);
You'll want to do this:
User.findOne({}, function(err, user){
user.key_to_delete = undefined;
user.save();
});
I use mongoose and using any of the above functions did me the requirement. The function compiles error free but the field would still remain.
user.set('key_to_delete', undefined, {strict: false} );
did the trick for me.
At mongo syntax to delete some key you need do following:
{ $unset : { field : 1} }
Seems at Mongoose the same.
Edit
Check this example.
Try:
User.findOne({}, function(err, user){
// user.key_to_delete = null; X
`user.key_to_delete = undefined;`
delete user.key_to_delete;
user.save();
});
if you want to remove a key from collection try this method.
db.getCollection('myDatabaseTestCollectionName').update({"FieldToDelete": {$exists: true}}, {$unset:{"FieldToDelete":1}}, false, true);
Could this be a side problem like using
function (user)
instead of
function(err, user)
for the find's callback ? Just trying to help with this as I already had the case.
Mongoose document is NOT a plain javascript object and that's why you can't use delete operator.(Or unset from 'lodash' library).
Your options are to set doc.path = null || undefined or to use Document.toObject() method to turn mongoose doc to plain object and from there use it as usual.
Read more in mongoose api-ref:
http://mongoosejs.com/docs/api.html#document_Document-toObject
Example would look something like this:
User.findById(id, function(err, user) {
if (err) return next(err);
let userObject = user.toObject();
// userObject is plain object
});
the problem with all of these answers is that they work for one field. for example let's say i want delete all fields from my Document if they were an empty string "".
First you should check if field is empty string put it to $unset :
function unsetEmptyFields(updateData) {
const $unset = {};
Object.keys(updatedData).forEach((key) => {
if (!updatedData[key]) {
$unset[key] = 1;
delete updatedData[key];
}
});
updatedData.$unset = $unset;
if (isEmpty(updatedData.$unset)) { delete updatedData.$unset; }
return updatedData;
}
function updateUserModel(data){
const updatedData = UnsetEmptyFiled(data);
const Id = "";
User.findOneAndUpdate(
{ _id: Id },
updatedData, { new: true },
);
}
I believe that, if you desire remove a specific field into a collection, you should do this:
User.remove ({ key_to_delete: req.params.user.key_to_delete});
you can use
delete user._doc.key