This may be a basic question but I've looked through the github Cloudant library and the Cloudant documentation and deleting a specific document from the database is mentioned but never thoroughly explained. It's very frustrating. The closest I've gotten to deleting a document is using an http request rather then the functions Cloudant library offers and I continuously get a "Document Update Conflict" even though I'm passing through the _rev of the document. Can anybody explain deleting a document from a Cloudant database using nodejs with an example to help sort this out. Thanks.
You can use the destroy method of nano like #JakePeyser has said, instead of using http APIs since you are using nodejs.
But since you are sending _rev and getting a "Document Update Conflict" error, it leads me to doubt if you have the latest _rev with you. "Document Update Conflict" happens mostly if the local _rev doesn't match the remote _rev. I would therefore suggest wrapping your destroy function in a get function. So an update to #JakePeyser's example would be:
var nano = require("nano")("cloudantURL"),
db = nano.db.use("yourDB");
db.get(docUniqueId, function(err, body) {
if (!err) {
var latestRev = body._rev;
db.destroy(docUniqueId, latestRev, function(err, body, header) {
if (!err) {
console.log("Successfully deleted doc", docUniqueId);
}
});
}
})
It depends what node module you are using for communicating with Cloudant. With the nano driver, you can use the destroy method to delete a document. See the following code example:
var nano = require("nano")("cloudantURL"),
db = nano.db.use("yourDB");
db.destroy(docUniqueId, docRevNum, function(err, body, header) {
if (!err) {
console.log("Successfully deleted doc", docUniqueId);
}
});
Key
cloudantURL - URL of your Cloudant instance, with username and password embedded
yourDB - your database name
docUniqueId - Unique ID of the doc you want to delete
docRevNum - Revision number of the doc you want to delete
Sample script to delete/destroy a doc from a collection "mytable" based on the value of the field "fkId".
var Cloudant = require('cloudant');
var Config = require('config-js');
var config = new Config('./settings.js');
var username = config.get('CLOUDANT_USER');
var password = config.get('CLOUDANT_PASWORD');
var cloudant = Cloudant({account:username, password:password});
var db = cloudant.db.use('mytable');
var key = 'fkId';
var value = '11234567890';
...
...
db.list({
'include_docs': true
}, function (err, body) {
/* istanbul ignore next */
if (err)
res.json({success: false, msg: 'Unable to fetch documents'});
else {
var rows = body.rows;
var items = [];
var rec_found = false;
rows.forEach(function (row) {
if (row.doc[key] === value) {
rec_found = true;
items.push(row.doc);
}
});
if (items.length === 0) {
console.log("No record found with fkId: "+ value);
res.json({success: true, msg: 'No record found with fkId: '+ value});
} else {
var docId = items[0]._id;
var docRev = items[0]._rev;
db.destroy(docId, docRev, function(err) {
if (!err) {
console.log("Successfully deleted doc with fkId: "+ value);
res.json({success: true, msg: 'Successfully deleted the item from the database.'});
} else {
res.json({success: false, msg: 'Failed to delete with fkId from the database, please try again.'});
}
});
}
}
});
Related
I've created an AWS account and want to use MongoDB Atlas with AWS Lambda.
The only dependency I've downloaded is mongodb locally.
npm install mongodb
Driver based connection string given from mongoDB Atlas for Nodejs is
var uri = "mongodb+srv://kay:myRealPassword#cluster0.mongodb.net/test";
MongoClient.connect(uri, function(err, client) {
const collection = client.db("test").collection("devices");
// perform actions on the collection object
client.close();
});
I think the connection is successful, because err parameter is NULL.
But I cannot figure out how to create collection, how to find results, how to insert documents.
I've tried this code
module.exports.hello = (event, context, callback) => {
var MongoClient = require('mongodb').MongoClient;
var uri = "mongodb+srv://kay:myRealPassword#cluster0.mongodb.net/test";
MongoClient.connect(uri, function(err, client) {
const collection = client.db("test").collection("devices");
collection.insert( { "msg" : "My First Document" } );
var results = client.db("test").collection("devices").find();
console.log(results);
client.close();
callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event });
});
};
but it returns (in Windows console) a huge Object in JSON format, its like a configuration data (not a query result)
enter image description here
I'm executing this code locally by
sls invoke local --function hello
The general idea is to check if there is an error in the connection, the insert, and so on. Take at look at this error checking:
if (error) return 1;
There are more sophisticated methods, but for your case this should do the work.
This is a example of how it show look your script:
MongoClient.connect(uri, (error, client) => {
if (error) return 1; // Checking the connection
console.log('Connection Successful');
var db = client.db('mydb'); // Your DB
let newDocument = { "msg" : "My First Document" }; // Your document
db.collection('mycollection').insert(newDocument, (error, results) => { // Your collection
if (error) return 1; // Checking the insert
console.log('Insert Successful');
})
db.collection('mycollection')
.find({})
.toArray((error, accounts) => {
if (error) return 1; // Checking the find
console.log('Find Successful');
console.log(accounts);
return 0;
})
})
And you should have an output like this:
Connection Successful
Insert Successful
Find Successful
[ { _id: 5a857dd2c940040d85cbe5f2, msg: 'My First Document' } ]
If your output is not like this, well the missing log would point the place where you have your error.
I am currently writing an API in NodeJS using express that retrieves data from a Sqlite database. The table containing the data, called DATA, to be retrieved has three columns:
ID - Integer
VALUE - Real
DATERECORDED - Integer
The data from the last five months is to be returned, and to do this, I am using the following query:
SELECT ID, VALUE FROM DATA WHERE DATERECORDED BEWTEEN date('now') AND date('now', '-5 months')
I recently removed several records from the database and entered new records. However, when I make a GET request to my API, I still get back the data that would've been returned when the old records were contained in the database. I even deleted all of the records in the database, but the old results are still being returned. Is there anyway that I can prevent this caching ?
I have also tried setting the cache_size to 0. The query is being used in the following code:
app.get('/get-data', function(req, res) {
console.log('Sending performance');
var stmnt = // query comes here
if(!exists) {
res.send({});
} else {
var db = new sqlite3.Database(db_path);
db.all(stmnt, function(err, rows) {
if(err) {
res.send({});
}
if(rows) {
var docs = {};
var by_id = _.groupBy(rows, function(row) {
return row.ID;
});
for(var key in by_id) {
if(by_isp.hasOwnProperty(key)) {
docs[key] = _.map(by_id[key], 'VALUE');
}
}
res.send(docs);
} else {
res.send({});
}
});
db.close();
}});
I am using node-mongodb-native in my application. I send multiple POST requests to nodejs server to save/update each documents, but only one document is getting updated and all other document are not changing. The data received in the server is correct.
save : function(req,res) {
data = req.body;
if(!data._id){
data._id = new ObjectID();
}else{
data._id = ObjectID(data._id);
}
mColl(req.params.collname, function (collection,db) {
collection.save(data, {safe:true}, function(err, result) {
if(err){
res.send(err);
}
else {
res.send(result);
}
});
});
}
I am not getting the response for the request also.
For starters, don't do this:
data = req.body;
When a new request comes in, you're overwriting the (global!) data variable, and all kinds of undefined stuff can happen. So always declare a new variable:
var data = req.body;
I am new to node.js and mongodb and I have the following problem:
I need to drop all collections from my mongodb from node.js file. I have such a function:
service.dropCollections = function(db, colls){
for(var i = 0; i < colls.length; i++){
var name = colls[i].name;
db.dropCollection(name, function(err) {
if(!err) {
console.log( name + " dropped");
} else {
console.log("!ERROR! " + err.errmsg);
}
});
}
}
And I am using it in the following function:
service.clearDB = function() {
var MongoClient = require('mongodb').MongoClient
, format = require('util').format;
MongoClient.connect('mongodb://127.0.0.1:27017/shiny_d', function(err, db){
if(err) throw err;
db.collectionNames(function(err, collections){
if(!err){
service.dropCollections(db, collections);
} else {
console.log("!ERROR! "+ err.errmsg);
}
service.showCollections();
});
});
}
As an output I have
!ERROR! ns not found
shiny_db.physicalinfos
Dunno what to do right now. I'll be very thankful for your help.
Ain't it more faster, easier and less error prone if you just drop the entire database?
db.dropDatabase();
At least from the Mongo CLI, whenever you access an inexistent DB, it'll be persisted the soon you create data. That's the same as dropping all collections from it.
I haven't tried MongoDB for anything except studying yet, so I don't know much about permissions. So, probably the only problem of dropping the entire DB would be the permissions of your users that would be lost (I believe).
If this script you're trying to create is not for production, then you're good to go with dropping the DB.
I found an answer. First of all I've made mistake in my connection it should be like following: 'mongodb://127.0.0.1:27017/shiny_db'. The second mistake was in the name of collection. It was like 'db_name.coll_name', that's why db.dropCollection(name, callback) couldn't find particular collection and because of it I had mistake ns not found. So I've used following mechanism to separate db_name from coll_name:
var name = colls[i].name.substring('shiny_db.'.length); and I've added checking for "system" collection.
Final code looks like following:
service.clearDB = function() {
var MongoClient = require('mongodb').MongoClient
, format = require('util').format;
MongoClient.connect('mongodb://localhost/shiny_db', function(err, db) {
if(err) throw err;
db.collectionNames(function(err, collections){
if(!err){
service.dropCollections(db, collections);
} else {
console.log("!ERROR! "+ err.errmsg);
}
});
});
}
service.dropCollections = function(db, colls){
for(var i = 0; i < colls.length; i++){
var name = colls[i].name.substring('shiny_db.'.length);
if (name.substring(0, 6) !== "system") {
db.dropCollection(name, function(err) {
if(!err) {
console.log( name + " dropped");
} else {
console.log("!ERROR! " + err.errmsg);
}
});
} else {
console.log(name + " cannot be dropped because it's a system file");
}
}
}
Hope it will help someone!
listCollections gives you an array of collection names as strings.
It looks like you may be confusing it with something that returns an array of collection objects like maybe db.collections()
I'm building out an api using Node, MongoDB and Mongoose. One thing that is bugging me is that you can't seem to set multiple fields at once:
app.put('/record/:id', function(req, res) {
Record.findById(req.params.id, function(err, doc) {
if (!err) {
doc.update(req.params);
doc.save();
...
However, it seems that you have to work out the update query and run it on the Model object rather than on the document object. Unless you want to assign individual properties and run save() at the end.
Is there any way of accomplishing this without having to write a Mongo query?
jsaak's answer is good but doesn't work for nested objects. I elaborated on his answer by searching and setting nested objects.
I added these functions to a utility.js file
var _ = require('underscore');
exports.updateDocument = function(doc, SchemaTarget, data) {
for (var field in SchemaTarget.schema.paths) {
if ((field !== '_id') && (field !== '__v')) {
var newValue = getObjValue(field, data);
console.log('data[' + field + '] = ' + newValue);
if (newValue !== undefined) {
setObjValue(field, doc, newValue);
}
}
}
return doc;
};
function getObjValue(field, data) {
return _.reduce(field.split("."), function(obj, f) {
if(obj) return obj[f];
}, data);
}
function setObjValue(field, data, value) {
var fieldArr = field.split('.');
return _.reduce(fieldArr, function(o, f, i) {
if(i == fieldArr.length-1) {
o[f] = value;
} else {
if(!o[f]) o[f] = {};
}
return o[f];
}, data);
}
implement as:
var util = require('./utility');
app.put('/record/:id', function(req, res) {
Record.findById(req.params.id, function(err, doc) {
if (!err) {
utils.updateDocument(doc, Record, req.params);
doc.save();
...
Maybe this has changed since this question was first asked, but you can update multiple paths in Mongoose with the set method ike:
// object
doc.set({
path : value,
path2 : {
path : value
}
});
doc.save();
References
http://mongoosejs.com/docs/api.html#document_Document-set
direct updating is not recommended according to this document:
http://mongoosejs.com/docs/2.7.x/docs/updating-documents.html
i solved it like this:
Book.findOne({isbn: req.params.isbn}, function (err, book){
if (err) {
res.send(422,'update failed');
} else {
//update fields
for (var field in Book.schema.paths) {
if ((field !== '_id') && (field !== '__v')) {
if (req.body[field] !== undefined) {
book[field] = req.body[field];
}
}
}
book.save();
}
});
If you want to update the entire document , you can delete the document based on its id and store the entire object again.
That object must contain data for each and every fields of the mongo document.
Here is an example.
mongoDBCollectionObject.findOneAndRemove({ // -- it will delete the entire document
_id: req.body.fieldsdata._id // here fiedsdata is exact copy with modification of previous data
}, function(err, data) {
var newFieldsData = new mongoDBCollectionObject(fieldsdata); //-- fieldsdata updated data
newFieldsData.save(function(err, data) { // save document to that collection with updated data
if (err) {
console.log(err);
} else
res.json({
success: true
});
});
})
To clarify the question, it looks like you are taking the Request parameters and using those to find and update the given document.
Is there any way of accomplishing this without having to write a Mongo query?
The obvious answer is to update the Model object with the value from the Request. Which is what you suggest...
Unless you want to assign individual properties and run save() at the end.
But it seems like you don't want to do this? It sounds like you want to update the Model object directly from the Request object?
You can do this if you really want. You just loop through req.params and set the doc values where appropriate.
for(var i in req.params) {
if(req.params[i] != doc[i]){
doc[i] = req.params[i];
}
}
It should be as simple as this. However, you only want to do this if you have a whole bunch of validation code on the Model objects. The whole point to the Model is that you don't want to get random data in the DB. The line above will generically "set" the correct values, but you'll definitely need to include code for authentication, authorization and validation around that simple for loop.
try to updating the collection without the find, like this
Record.update({_id:req.params.id}, {$set: { field: request.field }}, {upsert: true}, function(err{...})
The option upsert create the document if not exist.
In case you have a new object and want to update whole object in the database, you can update multiple fields at once like this:
find the object
get all schema paths (fields)
save the new object.
SomeModel.findOne({ 'id': 'yourid' },function (err, oldObject) {
if (err) return handleError(err);
// get all schema paths (fields)
SomeModel.schema.eachPath(function(path) {
// leave __id and __v alone
if (path != '_id' && path != '__v') {
// update the data from new object
oldObject[path] = newObject[path];
}
})
oldObject.save(function(err) {
if (err)
console.log(err)
});
})
A neat and clean approach would be using async await and findOneAndRemove along with create Here is the sample code
try {
let resp = await this.findOneAndRemove({ _id: req.body._id });
let entry = await this.create(req.body);
} catch (err) {
}
Don't Forget to mark this whole function as async