Monk: how to get the last N records? - mongodb

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.

Related

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!

Find and count all in Sails.js + Waterline

Is there a way to do select query and count_all query via single method?
For pagination purposes we need to know total number of items so we can calculate and show number of pages.
getLength: function(req, res) {
Posts.find({}).exec(function(err, items){
return items.length;
});
}
Check out Sails.Js - How I do pagination in sails.Js for pagination in Waterline.
To get the total number of items, you can use:
Post.count().exec(function (err, nbOfInstances) {
if(err) return res.negociate(err);
return res.ok(nbOfInstances);
});
First you query and get data after that you delete limit, skip parameters and get count
delete query._criteria.limit;
delete query._criteria.skip;
Model.count(query._criteria).exec(function countCB(error, count) {
});
I also couldn't find any built-in method to do that in one request so I do it like this:
let queryParams = {},
pageNo = 1,
perPage = 10;
Post.count(queryParams)
.then(_count=>{
return {posts_count: _count,
posts: Post.find(queryParams).paginate({page: pageNo, limit: perPage})};
})
.then(res.ok)
.catch(err=>res.negotiate(err.message));
OUTPUT:
/*
{
posts_count: 0,
posts: []
}
*/

How can you display with MongoDB error in MeteorJs?

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.

Remove multiple documents from mongo in a single query

I have a list of mongo '_id' which I want to delete. Currently I am doing this
# inactive_users --> list of inactive users
for item in inactive_users:
db.users.remove({'_id' : item})
but my problem is the list is too huge... (it might go 100,000 +). So querying for every item in list will only increase the load on server. Is their a way to pass the entire list in mongo query so that I dont have to fire query again and again.
Thank you
db.users.deleteMany({'_id':{'$in':inactive_users}})
List them all and use $in operator:
db.users.remove({_id:{$in:[id1, id2, id3, ... ]}})
You need to pass the ids in a specific format using ObjectId():
db.users.remove({_id: {$in: [ObjectId('Item1'), ObjectId('Item2'), ObjectId('Item2')]}});
Remove doesn't accept integer - you have to use ObjectId instance with _id format as a string.
var collection = db.users;
var usersDelete = [];
var ObjectID = req.mongo.ObjectID; //req is request from express
req.body.forEach(function(item){ //req.body => [{'_id' : ".." , "name" : "john"}]
usersDelete.push(new ObjectID(item._id));
});
collection.remove({'_id':{'$in': usersDelete}},function(){
//res.json(contatos);
});
I had the same question and ran across these answers but it seems the MongoDB manual is recommending deleteMany instead of remove. deleteMany returns the delete count as well as an acknowledgement of the write concern (if the operation succeeded).
const ids = [id1, id2, id3...];
const query = { _id: { $in: ids} };
dbo.collection("users").deleteMany(query, function (err, obj) {
if (err) throw err;
});
Or with an arrow function:
const ids = [id1, id2, id3...];
const query = { _id: { $in: ids} };
dbo.collection("users").deleteMany(query, (err, obj) => {
if (err) throw err;
});
Or better yet, with a promise:
const ids = [id1, id2, id3...];
const query = { _id: { $in: ids} };
dbo.collection("users").deleteMany(query)
.then(result => {
console.log("Records Deleted");
console.log(JSON.stringify(result));
//for number removed...
console.log("Removed: " + result["n"]);
})
.catch(err => {
console.log("Error");
console.log(err);
});

MapReduce, MongoDB and node-mongodb-native

I'm using the node-mongodb-native library to run a MapReduce on MongoDB (from node.js).
Here's my code:
var map = function() {
emit(this._id, {'count': this.count});
};
var reduce = function(key, values) {
return {'testing':1};
};
collection.mapReduce(
map,
reduce,
{
query:{ '_id': /s.*/g },
sort: {'count': -1},
limit: 10,
jsMode: true,
verbose: false,
out: { inline: 1 }
},
function(err, results) {
logger.log(results);
}
);
Two questions:
1) Basically, my reduce function is ignored. No matter what I put in it, the output remains just the result of my map function (no 'testing', in this case). Any ideas?
2) I get an error unless an index is defined on the field used for the sort (in this case - the count field). I understand this is to be expected. It seems inefficient as surely the right index would be (_id, count) and not (count), as in theory the _id should be used first (for the query), and only then the sorting should be applied to the applicable results. Am I missing something here? Is MongoDB inefficient? Is this a bug?
Thanks! :)
The reason why the reduce function is never called is due to you emitting a single value for each key so there is no reason for the reduce function to actually execute. Here is an example of how you trigger the reduce function
collection.insert([{group: 1, price:41}, {group: 1, price:22}, {group: 2, price:12}], {w:1}, function(err, r) {
// String functions
var map = function() {
emit(this.group, this.price);
};
var reduce = function(key, values) {
return Array.sum(values);
};
collection.mapReduce(
map,
reduce,
{
query:{},
// sort: {'count': -1},
// limit: 10,
// jsMode: true,
// verbose: false,
out: { inline: 1 }
},
function(err, results) {
console.log("----------- 0")
console.dir(err)
console.dir(results)
// logger.log(results);
}
);
Notice that we are emitting by the "group" key meaning there is n >= 0 entries grouped by the "group" key. Since you are emitting _id each key is unique and thus the reduce function is not needed.
http://docs.mongodb.org/manual/reference/command/mapReduce/#requirements-for-the-reduce-function