Only one document in dbs - how to update it? - javascript

I have a node js program where I only want to allow one document in a specific collection.
Mongo Schema:
var DefaultPollSchema = new mongoose.Schema({
milliseconds: Number
});
So the collection always looks like this:
> db.defaultpolls.find()
{ "_id" : ObjectId("58500051a4b71d0c4d5c6ab3"), "milliseconds" : 15000, "__v" : 0 }
I want to create an API for updating this value, however I do not want to use the objectId in order to do the update. Since I will only have one document in this collection - is there a way to do it?
I tried using this:
router.put('/update', function(req, res, next) {
var milliseconds = req.body.milliseconds;
defaultPoll.updateMany({}, {$set: {milliseconds: milliseconds}}, function (err, interval){
if (err) {
res.json(err);
} else {
res.json(interval);
}
})
});
However this gives me the following error:
TypeError: Object function model(doc, fields, skipId) {
if (!(this instanceof model)) {
return new model(doc, fields, skipId);
}
Model.call(this, doc, fields, skipId);
} has no method 'updateMany'
Is there any other way to write the API?
Thanks

The method for Mongoose updates is called update, so the approach is fine, but it should be:
defaultPoll.update({}, {$set: {milliseconds: milliseconds}}, function (err, raw) { ...

JohnnyHK's solution will not work. Mongoose documentation mentions the following:
Passing an empty object {} as the doc will result in a no-op unless
the overwrite option is passed. Without the overwrite option set, the
update operation will be ignored and the callback executed without
sending the command to MongoDB so as to prevent accidently
overwritting documents in the collection.
So the following code should work in your case
(Note the { overwrite: true } as options):
router.put('/update', function(req, res, next) {
var milliseconds = req.body.milliseconds;
defaultPoll.update({}, {$set: {milliseconds: milliseconds}}, { overwrite: true }, function (err, interval){
if (err) {
res.json(err);
} else {
res.json(interval);
}
})
});

Related

After Summing Amounts Getting 'Converting circular structure to JSON' Error in MongoDB [duplicate]

I have some code that pulls all documents from a collection and puts it onto a webpage. a simplified version looks like this:
var mongodb = require("mongodb"),
express = require("express"),
mongoServer = new mongodb.Server('localhost', 27017),
dbConnector = new mongodb.Db('systemMonitor', mongoServer),
db;
var app = new express();
app.get('/drives', function(req, res) {
db.collection('driveInfo', function(err, collection) {
if (err) throw err;
collection.find({}, function(err, documents) {
res.send(documents);
});
});
});
dbConnector.open(function(err, opendb) {
if (err) throw err;
db = opendb;
app.listen(80);
});
I have a driveInfo collection which contains a long list of documents. Each document contains nested objects. What I would like to do, is whenever someone visits /drives in their browser, to print the entire collection as a json object so that I can grab everything with jquery later (beginnings of an api)
However, I get an error saying "TypeError: Converting circular structure to JSON". The error on the page points to this line of code:
collection.find({}, function(err, documents) {
res.send(documents);
});
I'm unsure what the problem is, or where the self-reference is. Am I not querying the collection properly?
Not sure what version of the API you are using, but i think that your syntax might be wrong looking at the API spec:
http://docs.mongodb.org/manual/reference/method/db.collection.find/
This is the declaration:
db.collection.find(<criteria>, <projection>)
And you are definitely misusing the projection parameter. Passing a callback like you are doing seems to return the db object in the result, which is causing the circular error during JSON serialization in express.
The correct code for the find all operation should be something like:
collection.find({}).toArray(function(error, documents) {
if (err) throw error;
res.send(documents);
});
In my case I was getting the error because I was querying(using mongoose find method) without doing an await. Please see below
Query that gave the error (as I haven't executed this query using await) :
const tours = Tour.find({
startLocation: {
$geoWithin: { $centerSphere: [[longitude, latitude], radius] }
}
});
Error that I got on postman due to this :
"message": "Converting circular structure to JSON\n --> starting at object with constructor 'NativeTopology'\n | property 's' -> object with constructor 'Object'\n | property 'sessionPool' -> object with constructor 'ServerSessionPool'\n --- property 'topology' closes the circle"
How I got rid of the above error (added await) :
const tours = await Tour.find({
startLocation: {
$geoWithin: { $centerSphere: [[longitude, latitude], radius] }
}
});
callback option is from Mongoose not from MongoDB see docs.
// Mongoose Docs : callback option
MyModel.find({ name: 'john', age: { $gte: 18 }}, function (err, docs) {});
// Example
app.get( '/api/users' , (req,res,done)=>{
let getUsers = NewUser.find({},(err,data)=>{
if(err) return done(err);
res.json(data)
});
});
Look that the response is into callback that in your case it would be
YourModel.find({}, function(err, documents) {
if(err) return done(err);
res.send(documents); // <-- here
});
// <-- not here
In Mongo there is a cursor method to access the documents next() see docs :
var myCursor = db.bios.find( );
var myDocument = myCursor.hasNext() ? myCursor.next() : null;
if (myDocument) {
var myName = myDocument.name;
print (tojson(myName));
}
You can find CRUD operations in mongo docs at manual/crud. In Query Documents you will see db.inventory.find( {} ) : To select all documents in the collection, pass an empty document as the query filter parameter to the find method.
Async/Await function solution : Mongo Docs
app.get( '/api/users' , async (req,res)=>{
const getUsers = await NewUser.find({});
res.json( getUsers );
})
< callback > solution : Mongoose Docs.
app.get( '/api/users' , (req,res,done)=>{
let getUsers = NewUser.find({},(err,data)=>{
if(err) return done(err);
res.json(data)
});
});
const res1 = await db.collection("some-db").find()
Here, res1 will contain a "cursor" which has a circular structure, hence the given error is thrown.
Try adding const res2 = await res1.toArray() to the code.
Here, res2 will now contain an array of documents, pointed by cursor res1, which is the documents you were querying for.

delete property doesn't work in node.js

I wonder why I can't delete password object, my console result shows the password is still there, I wonder why.
User.comparePassword(password, user.password , (err, result) => {
if (result === true){
User.getUserById(user._id, (err, userResult) => {
delete userResult.password
const secret = config.secret;
const token = jwt.encode(userResult, secret);
console.log(userResult)
res.json({success: true, msg: {token}});
});
} else {
res.json({success: false, msg: 'Error, Incorrect password!'});
}
}
There are multiple solutions to your problem. You cannot delete property from Mongoose query, because you get some Mongoose wrapper. In order to manipulate object you need to transform it to JSON object. So there are three possible way that I can remember to do that:
1) Call toObject method mongoose object (userResult) like this:
let user = userResult.toObject();
delete user['password'];
2) Redefine toJson method of User model:
UserSchema.set('toJSON', {
transform: function(doc, ret, options) {
delete ret.password;
return ret;
}
});
3) Query can return object without specified field, so that you don't need to delete anything:
User.findById(user._id, {password: 0}, function (err, userResult) {
...
}

Node JS Multiple Select

Hi i am trying to use two selects in one JS file in node js and sql server. I am unable to figure out the syntax for this. I need a select to get all the persons from a table and another select to count the total number of persons in that table.Will it be possible to put those two selects in a single JS file. If so can someone help me with the syntax?
Here is the code i tried and i am getting the error
"cant Set headers after they are sent"
var sql = require("mssql");
var dbConfig = {
server: "XXXXX",
database: "XXXXX",
user: "XXXXX",
password: "XXXX",
port: 1433
};
exports.list = function(req, res){
sql.connect(dbConfig, function (err) {
if (err) console.log(err);
var request = new sql.Request();
request.query('select * from PERSON', function (err, recordset) {
if (err)
console.log(err)
else
console.log(recordset)
res.render('personinfo_itwx', { data: recordset });
});
request.query('select count(*) from PERSON', function (err, recordset) {
if (err)
console.log(err)
else
console.log(recordset1)
res.render('personinfo_itwx', { data: recordset1 });
});
});
};
#Aditya I'm not sure it's the best way to do so, although I would simply make two different requests, in order to achieve what you need. As I mentioned my in my comment, easiest way, would be to use (for instance) async library. And here's example you've asked for.
WARNING: I did not look at mysql docs
const async = require('async')
// {
async.series([
function(next)
{
new sql.Request()
.query('SELECT * from PERSON', next(err, resultList))
},
function(next)
{
new sql.Request()
.query('SELECT COUNT(*) from PERSON', next(err, count))
}
], (err, result) =>
{
/*
err: String
- if any of the shown above return an error - whole chain will be canceled.
result: Array
- if both requests will be succesfull - you'll end up with an array of results
---
Now you can render both results to your template at once
*/
})
// }
Surely, if you want manipulate with errors or results once you get them - you always may push error and results to new function, play with your data, and return the callback afterwards. Like so:
function(next)
{
new sql.Request()
.query('SELECT * from PERSON', (err, resultList) =>
{
if (err)
{
return next(err, null)
}
/*
data manipulation
*/
return next(null, resultList)
})
},

How to update document on pre or post query hook in mongoose?

I am trying to update a field on a query hook. For example:
var mySchema = new Schema({
name: String,
queryCount: {type: Number, default:0}
});
I want to increment and update queryCount field on each find or findOne query.
mySchema.post('find', function (doc) {
// here is the magic
});
I have tried a few things but no success so far. Can I achieve this in model or do I have to do it in the controller?
What you want is a post init hook
mySchema.post('init', function (doc) {
doc.queryCount++;
doc.save();
});
Alternatively, you could use a mongoose static method which internally calls findAndUpdate()
mySchema.statics.findWithIncrement = function (query, callback) {
this.findAndUpdate(query, { $inc: { queryCount: 1 })
.exec(function(err, res) {
if (err) return callback(err);
//Handle response
});
}
And then use the method in your controllers:
MyModel.findWithIncrement({name: "someName"}, function (err, result) {
})

mongodb nodejs - converting circular structure

I have some code that pulls all documents from a collection and puts it onto a webpage. a simplified version looks like this:
var mongodb = require("mongodb"),
express = require("express"),
mongoServer = new mongodb.Server('localhost', 27017),
dbConnector = new mongodb.Db('systemMonitor', mongoServer),
db;
var app = new express();
app.get('/drives', function(req, res) {
db.collection('driveInfo', function(err, collection) {
if (err) throw err;
collection.find({}, function(err, documents) {
res.send(documents);
});
});
});
dbConnector.open(function(err, opendb) {
if (err) throw err;
db = opendb;
app.listen(80);
});
I have a driveInfo collection which contains a long list of documents. Each document contains nested objects. What I would like to do, is whenever someone visits /drives in their browser, to print the entire collection as a json object so that I can grab everything with jquery later (beginnings of an api)
However, I get an error saying "TypeError: Converting circular structure to JSON". The error on the page points to this line of code:
collection.find({}, function(err, documents) {
res.send(documents);
});
I'm unsure what the problem is, or where the self-reference is. Am I not querying the collection properly?
Not sure what version of the API you are using, but i think that your syntax might be wrong looking at the API spec:
http://docs.mongodb.org/manual/reference/method/db.collection.find/
This is the declaration:
db.collection.find(<criteria>, <projection>)
And you are definitely misusing the projection parameter. Passing a callback like you are doing seems to return the db object in the result, which is causing the circular error during JSON serialization in express.
The correct code for the find all operation should be something like:
collection.find({}).toArray(function(error, documents) {
if (err) throw error;
res.send(documents);
});
In my case I was getting the error because I was querying(using mongoose find method) without doing an await. Please see below
Query that gave the error (as I haven't executed this query using await) :
const tours = Tour.find({
startLocation: {
$geoWithin: { $centerSphere: [[longitude, latitude], radius] }
}
});
Error that I got on postman due to this :
"message": "Converting circular structure to JSON\n --> starting at object with constructor 'NativeTopology'\n | property 's' -> object with constructor 'Object'\n | property 'sessionPool' -> object with constructor 'ServerSessionPool'\n --- property 'topology' closes the circle"
How I got rid of the above error (added await) :
const tours = await Tour.find({
startLocation: {
$geoWithin: { $centerSphere: [[longitude, latitude], radius] }
}
});
callback option is from Mongoose not from MongoDB see docs.
// Mongoose Docs : callback option
MyModel.find({ name: 'john', age: { $gte: 18 }}, function (err, docs) {});
// Example
app.get( '/api/users' , (req,res,done)=>{
let getUsers = NewUser.find({},(err,data)=>{
if(err) return done(err);
res.json(data)
});
});
Look that the response is into callback that in your case it would be
YourModel.find({}, function(err, documents) {
if(err) return done(err);
res.send(documents); // <-- here
});
// <-- not here
In Mongo there is a cursor method to access the documents next() see docs :
var myCursor = db.bios.find( );
var myDocument = myCursor.hasNext() ? myCursor.next() : null;
if (myDocument) {
var myName = myDocument.name;
print (tojson(myName));
}
You can find CRUD operations in mongo docs at manual/crud. In Query Documents you will see db.inventory.find( {} ) : To select all documents in the collection, pass an empty document as the query filter parameter to the find method.
Async/Await function solution : Mongo Docs
app.get( '/api/users' , async (req,res)=>{
const getUsers = await NewUser.find({});
res.json( getUsers );
})
< callback > solution : Mongoose Docs.
app.get( '/api/users' , (req,res,done)=>{
let getUsers = NewUser.find({},(err,data)=>{
if(err) return done(err);
res.json(data)
});
});
const res1 = await db.collection("some-db").find()
Here, res1 will contain a "cursor" which has a circular structure, hence the given error is thrown.
Try adding const res2 = await res1.toArray() to the code.
Here, res2 will now contain an array of documents, pointed by cursor res1, which is the documents you were querying for.

Categories