Identify last document from MongoDB find() result set - mongodb

I'm trying to 'stream' data from a node.js/MongoDB instance to the client using websockets. It is all working well.
But how to I identify the last document in the result? I'm using node-mongodb-native to connect to MongoDB from node.js.
A simplified example:
collection.find({}, {}, function(err, cursor) {
if (err) sys.puts(err.message);
cursor.each(function(err, doc) {
client.send(doc);
});
});

Since mongodb objectId contatins creation date you can sort by id, descending and then use limit(1):
db.collection.find().sort( { _id : -1 } ).limit(1);
Note: i am not familiar with node.js at all, above command is mongo shell command and i suppose you can easy rewrite it to node.js.

Say I have companies collection. Below snippet gives me last document in the collection.
db.companies.find({},{"_id":1}).skip(db.companies.find().count()-1);
Code cannot rely on _id as it may not be on a specific pattern always if it's a user defined value.

Use sort and limit, if you want to use cursor :
var last = null;
var findCursor = collection.find({}).cursor();
findCursor.on("data", function(data) {
last = data;
...
});
findCursor.on("end", function(data) {
// last result in last
....
});

Related

Second parameter to limit fields in find() not working in Mongodb

Mongodb Database view
I want to omit the _id field in my result
MongoClient.connect("mongodb://localhost:27017/",function(err,client){
var db = client.db("customerDetails");
db.collection("customerName").find({},{ _id : 0}).toArray(function(error,result){
console.log(result);
client.close();
});
});
Looked up from w3 schools
But somehow its not working. I still get the _id field in my result object.
What am i missing ??
In version 3.0 of the mongodb driver, the second parameter to find() is the options object, not the projection document. See the documentation here. To send a projection document, set the projection property of the options document. E.g.
db.collection("customerName").find({}, { projection: { _id: 0 } })
Alternatively, use the project method:
db.collection("customerName").find({}).project({ _id: 0 })
In version 2.2 of the mongodb driver, the second argument of find was indeed the projection document. This has changed in the latest version (3.0). So some blog posts might not be up to date. See the relevant section of the 3.0 changelog here.
In version 3.4.9 of the mongodb you can simply achieve this by:
db.getCollection('data').find({}, { _id: 0 })
This should work. Using the boolean "false".
MongoClient.connect("mongodb://localhost:27017/",function(err,client){ var db = client.db("customerDetails"); db.collection("customerName").find({},{ _id : false}).toArray(function(error,result){ console.log(result); client.close(); }); });

Cannot remove on mongodb using mongoose?

Hi im trying to simply remove a document from a collection using mongoose but for some strange reason I cannot get it to work.
Here is the code:
function deleteUserevent()
{console.log('in delete User Event');
models.Userevent.remove({ _id: "5214f4050acb53fe31000004"}, function(err) {
if (!err){
console.log('deleted user event!');
}
else {
console.log('error');
}
});
}
Can anyone help me out on my syntax? I know the _id is stored as new ObjectId("5214f4050acb53fe31000004") but I have tried this with no joy?
Thanks.
In MongoDB, the "_id" field of documents is of type ObjectId, as you mentioned. This is not equal to a String, so running the query
db.userevent.remove({ _id: "5214f4050acb53fe31000004"});
will not match anything, and will not remove anything. Instead, you must search for a document where the _id field is an ObjectId with that value:
db.userevents.remove({ _id: ObjectId("5214f4050acb53fe31000004")});
In mongoose, you can use the findByIdAndRemove command to remove a document with a specific _id. This command takes either an ObjectId or a String as an argument, so
query = Userevent.findByIdAndRemove("5214f4050acb53fe31000004");
should work just fine.
Just add exec() after query.
It should work like this:
await models.Userevent.findByIdAndDelete("5214f4050acb53fe31000004").exec()

Getting Mongoose Schema's and Documents without knowing Schema / Collection names?

Short Version: I basically want to do what show collections does in the mongo shell, in mongoose.
Long Version:
I want to create an application that allows users to basically create their own Schema's > Collections > Documents using mongo + mongoose + node.js.
The first step of this application would be to show previously created Collections and their Documents. But since these would be created by a user their names are not known.
The code I've found that came closest was:
function find (collec, query, callback) {
mongoose.connection.db.collection(collec, function (err, collection) {
collection.find(query).toArray(callback);
});
}
But I don't know what the name of the collection is so I can't pass the 'collec' parameter.
So, anyone know how to get the list of collections without knowing their names?
I ended up using node-mongodb-native (the mongo driver that mongoose works on top of) to get the collection names:
var nmn_connect = require('mongoose/node_modules/mongodb').connect;
nmn_connect('mongo://localhost:27017/DATABASE', function(err, db) {
if(!err){
db.collectionNames(function(err, names){ // what I was looking for
if(!err){
console.log(names);
db.close();
}else{
console.log(err);
db.close();
}
});
}else{
console.log(err)
}
});
The Object returned by mongoose.connect() has no method similar to collectionNames() that I can find.
I know nothing of mongoose, but this page suggests that you could use mongoose.connection.collections to access all collections: http://mongoosejs.com/docs/api.html
each collection again should have a name attribute.
try this:
mongoose.connection.db.collectionNames(function (err, names) {
});

Finding an Embedded Document by a specific property in Mongoose, Node.js, MongodDB

For this app, I'm using Node.js, MongoDB, Mongoose & Express
So I have a Param Object that contains an array of Pivots, and I want to read certain data from the pivots as outlined below
---in models.js-------------------------
var Pivot = new Schema({
value : String
, destination : String
, counter : Number
});
var Param = new Schema({
title : String
, desc : String
, pivots : [Pivot]
});
------------- in main.js --------------
var Param = db.model('Param');
app.get('/:title/:value', function(req, res){
Param.findOne({"title":req.param('title')}, function(err, record){
console.log(record.pivots);
record.pivots.find({"value":req.param('value')}, function(err, m_pivot){
pivot.counter++;
res.redirect(m_pivot.destination);
});
record.save();
});
});
I know that the code works until console.log(record.pivots), since i got a doc collection with the right pivot documents inside.
However, there does not seem to be a find method to let me match an embedded document by the 'value' property defined in the schema. Is it possible to search through this array of embedded documents using .find() or .findOne() , and if not, is there some easy way to access it through mongoose?
varunsrin,
This should do it
app.get('/:title/:value', function(req, res) {
Param.findOne({'pivots.value': req.param('value'), "title":req.param('title')}},
function(err, record) {
record.pivot.counter++;
res.redirect(m_pivot.destination);
record.save();
});
});
Note the pluralization of the query to match the field name in your schema
You can querying using embedded document properties like this:
{'pivot.value': req.param('value')}}
Update in response to comment:
app.get('/:title/:value', function(req, res) {
Param.findOne({'pivot.value': req.param('value'), "title":req.param('title')}},
function(err, record) {
record.pivot.counter++;
res.redirect(m_pivot.destination);
record.save();
});
});
I solved it temporarily using a simple for loop to parse the object array as follows:
for (var i=0; i <record.pivots.length; i++){
if (record.pivots[i].value == req.param('value')){
res.redirect(record.pivots.destination);
}
}
However, I still think that Mongoose must have a simpler way of interacting with embedded documents - and this loop is somewhat slow, especially when the number of embedded documents grows large.
If anyone has any suggestions for a faster way to search this object array either in js or with a mongoose function, please post below.
the biggest problem with this is that if your req has some fields empty (that should act as wildcard), you will not find anything since mongo tries to match empty params as well, so searching for {"user":"bob", "color":""} is not the same as {"user":"bob", "color":"red"} or {"user":"bob"}. this means that you have to first create a query object and filter out any unused parameters before you pass it in, and if you create a query object, you can no longer do something like "user.name=..." because mongo interperets this as an error since it does not first resolve the object literal into a string.
Any ideas on this problem?
ps. You'd think it would be easy enough to make an object like:
user.name="bob"; user.color:"green"; user.signup.time="12342561"
and then just use user as a query object :/
I think you are looking for the "$in" keyword?
As in:
{a: {$in: [10, "hello"]}}
source: MongoDB Queries CheatSheet

mongoose node.js, query with $lt and $gt not working

I want to get all the pupils whose last mark is between 15 and 20. To do so, I perform the following query in my mongoDB using mongoose:
The models are working fine (all the other queries are ok).
Pupils.find({"marks[-1].value": {'$lt' : 20 }, "marks[-1].value" : { '$gt' : 15 }}, function(err, things){
This is not working, is there something I missed ?
* UPDATE *
I found something like:
Pupils.find({ "marks[-1].value": {$gt : 15, $lt : 20}});
But this does not work either. Is there a way to get the last mark of the marks array in this case ?
Lets consider your Pupils collection:
Pupils
{
_id,
Marks(integer),
LatestMark(int)
}
I suggest to add latest mark into Pupil document(as you can see at the document above), and update it each time when you adding new mark into nested collection.
Then you will able to query on it like this:
db.Pupils.find({ "LatestMark": {$gt : 15, $lt : 20}});
Also you can query latest mark using $where, but be care because:
Javascript executes more slowly than
the native operators, but is very flexible
I believe it's not working because the embedded collections in mongo are accessed like this:
"marks.0.value", although I haven't used mongoose.
Unfortunately for your scenario, I do not think there is a way to use negative indexing. (Mongo doesn't guarantee a preserved natural order unless you use a capped collection anyway though)
You may be able to accomplish this using Map/Reduce or a group command
http://www.mongodb.org/display/DOCS/MapReduce
This is tip than an answer.
Use double quotes for special key words like $elemMatch, $get, $lt etc while using mangoose.
In following code,$gt will not work properly.
var elmatch = { companyname: mycompany };
var condition = { company_info: { $elemMatch: elmatch } };
if(isValid(last_id)){
condition._id = { $gt: new ObjectId(last_id) };
}
console.log(condition);
User.find(condition).limit(limit).sort({_id: 1}).exec(function (err, lists) {
if (!err) {
res.send(lists);
res.end();
}else{
res.send(err);
res.end();
}
});
But this issue is solved when i'm using double quotes for special keywords
var elmatch = { companyname: mycompany };
var condition = { company_info: { "$elemMatch": elmatch } };
if(isValid(last_id)){
condition._id = { "$gt": new ObjectId(last_id) };
}
console.log(condition);
User.find(condition).limit(limit).sort({_id: 1}).exec(function (err, lists) {
if (!err) {
res.send(lists);
res.end();
}else{
res.send(err);
res.end();
}
});
I hope it will be helpful.