How can you display with MongoDB error in MeteorJs? - mongodb

I'm getting a strange error in Meteor. It allows me to update a count, but when I try to reverse the count, it won't update.
Template.listItem.events({
'click .remove': function(e, template) {
e.preventDefault();
ListItems.remove(this._id);
//Router.go('listPage', {_id: template.data._id});
},
'click .listItem': function(e, template) {
e.preventDefault();
var item = ListItems.findOne(this._id);
ListItems.update(this._id, {$set: { picked: true }});
Items.update(item.itemId, {$inc: {pickedCount: 1}});
},
'click .picked': function(e, template) {
e.preventDefault();
var item = ListItems.findOne(this._id);
console.log(item.itemId);
ListItems.update(this._id, {$set: { picked: false }});
Items.update({_id: item.itemId}, {$inc: {pickedCount: -1}});
}
});
The pickedCount is what I'm trying to revert. Everything I've read said this should work. How can I display the error from MongoDB if there is one? Is this the accepted syntax for decrementing a field in Mongo?

Most Meteor.call functions (or which Collection.update is one), take a last argument as a callback. From the docs:
callback Function Optional. If present, called with an error object as
the first argument and, if no error, the number of affected documents
as the second.
Hence, you can write your call to update as:
Items.update({_id: item.itemId}, {$inc: {pickedCount: -1}}, function (err) {
console.log("Error = ", err);
});
However, the error on the server console is likely to be more informative in your case.

Related

Why does MongoDB not update unless I call ".then res.json(...)" after findOneAndUpdate?

understanding questions here. I am doing a MERN setup website, and I was updating a field in my database like this:
router.post("/updateLogApprovementStatus", (req, res) => {
User.findOneAndUpdate(
{ _id: req.body.userId },
{ $set: { log: req.body.newData } }
).then(user => res.json(user.log));
});
But after doing repeated calls to the api with correct data, my data field wasn't updating. However, when I do this:
router.post("/updateLogApprovementStatus", (req, res) => {
User.findOneAndUpdate(
{ _id: req.body.userId },
{ $set: { log: req.body.newData } }
).then(user => res.json(user.log));
});
My database updates perfectly fine. All I did was adding a res.json(), which occurs after the update since it is in the "then" statement, which makes me wonder why it wored.
I am pretty sure that all I did was adding the then res.json() statement. Any clarifications on why this made it work?
Reason being : "The query executes if callback is passed else a Query object is returned." (bellow the returns section)
.then() isn't really a promise, it's disguised by mongoose but acts as an execution.
You can see it execute queries here
.exec() from the documentation "Executes the query" and returns a Promise (true one)
Mongoose queries are not promises. They have a .then() function for co
and async/await as a convenience. If you need a fully-fledged promise,
use the .exec() function.
If I understand your issue correctly, you should go with something like this:
User.findOneAndUpdate(
{ _id: req.body.userId },
{ $set: { log: req.body.newData } }
).exec();
The exec function will run the query and this way you don't have to handle the promise result.

What is the syntax for a mongoose query where I just want one property's value?

I am sending a query to mongoDB using mongoose. The collection is named Step. I want the result of this query to be an array of _id values, one per step. Currently I am getting all of the step objects in their entirety, because req.query isn't defined in this case.
service:
this.getSteps = function() {
return $http({
method: 'GET',
url: '/api/step'
})
.then(function(response) {
return response.data;
});
};
controller:
readStep: function (req, res) {
Step.find(req.query, function(err, result) {
if (err) {
res.status(500).send(err);
}
res.status(200).send(result);
});
}
Set the second parameter of the find query to '_id' to retrieve only the _id of the objects.
Step.find(req.query, '_id', function(err, result) {
This will return data like this:
[{_id: 123}, {_id: 234}]
If you want to get an array of the Step ids on their own, use the javascript map function like so
result = result.map(function(doc) {
return doc._id;
});
which will give you an array like this:
[123, 234]
You'll need to use query.select, something like as shown below:
Step.find(query).select({ "_id": 1}).then(....);
I'm not able to type much because I'm responding from my handheld.
Hope this help!

MongoDb/Mongoskin - CLEANLY Update entire document w/o specifying properties

All the examples I have seen for MongoDb & Mongoskin for update, have individual properties being updated, like so:
// this works when I specify the properties
db.collection('User').update({_id: mongoskin.helper.toObjectID(user._id)},
{'$set':{displayName:user.displayName}}, function(err, result) {
if (err) throw err;
if (result){ res.send(result)}
});
But what if I wanted the whole object/document to be updated instead:
// this does not appear to work
db.collection('User').update({_id: mongoskin.helper.toObjectID(user._id)}, {'$set':user},
function(err, result){
// do something
}
It returns the error:
// It appears Mongo does not like the _id as part of the update
MongoError: After applying the update to the document {_id: ObjectId('.....
To overcome this issue, this is what I had to do to make things work:
function (req, res) {
var userId = req.body.user._id
var user = req.body.user;
delete user._id;
db.collection('User').update({_id: mongoskin.helper.toObjectID(userId)},
{'$set':user}, function(err, result) {
if (err) throw err;
console.log('result: ' + result)
if (result){ res.send(result)}
});
})
It there a more elegant way of updating the whole document, instead of hacking it with:
delete user._id
If you want to update the whole object, you do not need a $set. I am not aware of mongoskin, but in shell you would do something like:
var userObj = {
_id: <something>
...
};
db.user.update({_id: user._id}, user);
Which I think can be translated in your mongoskin in the following way.
db.collection('User').update({_id: user._id}, user, function(){...})
But here is the problem. You can not update _id of the element in Mongo. And this is what your error tells you. So you can remove the _id from your user object and have it separately. Search by this separate _id and update with a user object without _id.

Monk: how to get the last N records?

I can't find where this is documented. By default, the find() operation will get the records from beginning.
router.get('/chat/get-messages', function(req, res) {
var db = req.db;
var collection = db.get('chatMessages');
collection.find({},{'limit':8},function(e,docs){
if (e) return next(e);
res.send(docs)
});
});
How can I get the N last inserted records ?
Sort by date descending to get the last N records, and then call reverse() on the docs array to put them back in ascending order:
collection.find({}, {sort: {date: -1}, limit: 8}, function(e, docs){
if (e) return next(e);
res.send(docs.reverse());
});
Ok I've found a workaround for what I wanted to do.
collection.find({},{sort: {"date": 1}},function(e,docs){
if (e) return next(e);
res.send(docs)
});
This returns the results ordered by date, I then sliced them on the client side :
$.getJSON( '/chat/get-messages', function( data ) {
data=data.slice(data.length -8, data.length);
...
});
I am still waiting for a proper way to achieve this though.

MongoDb get last few documents and the await tailable cursor

I want to get 5 last documents from a MongoDB collection, then keep tailing it for new documents. Can this be done at all with one query, or do I really need two queries? If two queries, what's the best way to achieve this without adding extra fields?
While answer in any language is fine, here's an example node.js code snippet of what I try to achieve (error handling omitted, and snippet edited based on first answer to the question):
MongoClient.connect("mongodb://localhost:1338/mydb", function(err, db) {
db.collection('mycollection', function(err, col) {
col.count({}, function(err, total) {
col.find({}, { tailable:true, awaitdata:true, timeout:false, skip:total-5, limit:5 }, function(err, cursor) {
cursor.each(function(err, doc) {
console.dir(doc); // print the document object to console
});
});
});
});
});
Problem: Above code prints all the documents starting from first one, and then waits for more. Options skip and limit have no effect.
Question: How to easily get 5 latest documents, then keep on tailing for more? Example in any language is fine, does not have to be node.js.
(Answer edited, it's useful to know this does not work with these versions.)
If collection was not tailable, you'd need to find out how many items there is, for that use count, and then use skip option, to skip first count-5 items.
This will NOT work, tailable and skip do not work together (MongoDB 2.4.6, node.js 0.10.18):
MongoClient.connect("mongodb://localhost:1338/mydb", function(err, db) {
db.collection('mycollection', function(err, col) {
col.count({ }, function(err, total) {
col.find({ }, { tailable: true, awaitdata: true, timeout: false, skip: total - 5, limit: 5 }, function(err, cursor) {
cursor.each(function(err, doc) {
console.dir(doc);
});
});
});
});
});