Updating Mongo document from Node - node.js

so I am inserting a document into mongo db as such
io.sockets.on('connection', function (socket) {
connectLog(socket.handshake.address.address);
function connectLog(ipAddress) {
db.collection('tracking', function (err, collection) {
var currentTime = new Date();
var doc={"ip":ipAddress, "connect": currentTime, "culture": "en" };
collection.insert(doc, function () { });
});
}
I have another event
function logout(id, disconnect) {
I'd like to update (or replace?) that record and add disconnect: (time) to it. How would I go about doing this? This way I can tell when a person connects and when they disconnect from the chat.
I am using socket.io so I'll know their exact disconnect time
Thank you in advance

First, read this about explicit vs. implicit disconnects: Socket.io: How to handle closing connections?. Basically, your handler for explicit logouts (which are good!) should call the same code as your disconnect handler, in case the user doesn't get a chance to explicitly logout.
So in addition to your logout code, you'll also want:
socket.on('disconnect', handleDisconnect)
And in that disconnect/logout handler, you'll want to find the most recent connection document for that user and update it.
collection.findAndModify(
{"address" : address}, //same address
[['connect', 'descending']], //the most recent, findAndModify only changes the first doc
{$set: {disconnect: currentTime}}, //set the disconnect time
function(err, object){/*deal with errors*/}
)

Related

MongoDB connections not releasing after query

I made some node app with using MongoDB and Socket.IO, and when I insert some documents, every operation isn't working. And I figured out that MongoDB doesn't insert documents after some documents inserted(I don't know how many exactly). So I checked connections with mongodb shell:
db.serverStatus().connections
before starting node app, it saids:
{ "current" : 1, "available" : 3275, "totalCreated" : NumberLong(639) }
after inserts some docs:
{ "current" : 51, "available" : 3225, "totalCreated" : NumberLong(708) }
turn off node app:
{ "current" : 1, "available" : 3275, "totalCreated" : NumberLong(708) }
This is the code of server side. (I'm using external MongoDB module so it can be little different from Original MongoDB module for node.js. this module is just simple wrapper for MongoDB with Promise based API)
const app = require('http').createServer();
const io = require('socket.io')(app);
const am2 = require('am2');
...
am2.connect('localhost', '...', { ... });
const sockets = {};
io.on('connection', (socket) => {
// save the socket into sockets object
sockets[socket.id] = socket;
// release socket on disconnection
socket.on('disconnect', () => {
delete sockets[socket.id];
});
...
// pseudo doc inserting event
socket.on('/insert/some/docs', (data) => {
am2.insert({ ... }).then( () => {
socket.emit('/after/insert/some/docs', {});
}).catch( ... );
});
});
when client emit '/insert/some/docs' event, server will insert document into MongoDB. first few tries works well, but after some insertion, it does not work anymore.
I think this happen because lot's of connections are still alive after insertion is done, but I don't know why. If it was RDBMS like MySQL, every connection must be close after operation is done, but in MongoDB, it should not be(as I know).
I don't know why this is happening, so it will be very appreciate give me a hand.
I solved this by releasing cursor after get data from MongoDB. Make sure to release, or it keeps your connection pool and makes your application not working.

Where need it call dropCollection using nodejs with mongodb?

I was doing a server using nodejs, it need get data from mongodb. I retrieve data after require(../db.js). Somebody said the mongodb needn't be close in nodejs,because nodejs is a single process.....
My question: Need I call dropCollection to close the collection after invoked the db function many times;and How to do?Where to do that? Please,Thanks.
You dont need to drop the collection after invoking db functions,simply call db.close() though it is not needed. But if you want to do it , you can do it as follows:
var dropRestaurants = function(db, callback) {
db.collection('restaurants').drop( function(err, response) {
console.log(response)
callback();
});
};

Saving reference to a mongoose document, after findOneAndUpdate

I feel like I'm encountering something completely simple, yet can not figure it out, will be glad, if you can help me.
I'm using mongoose + socket.io as CRUD between client and server. As I'm using sockets, there is a private scope individual for each client's socket, in which, for future use without making db find calls, I would like to store a reference of mongoose document, that I once found for this user.
One client is creanting a Room:
var currentroom;
client.on('roomcreate', function (data) {
currentroom = new Room({
Roomid: id,
UsersMeta: [UserMeta],
///other stuff///
})
currentroom.save(function (err, room) {
if (err) console.log(err);
else console.log('success');
});
});
Then, whenewer I want, on another creator's call I can just simply
currentroom.Roomnaid = data;
curretroom.save()
And it's working fine, the problem is - I do not understand how I can get the same reference on not creating, but Room search, for the moment i'm using this for search:
Room.findOneAndUpdate({ Roomid: roomid }, { $push: { UsersMeta: UserMeta}}, { new: false }, function (err, room) {
if (err) console.log(err);
console.log('room output:');
console.log(room);
client.emit('others', room);
})
The thing is, that in one call I want to:
1: find a doc in db,
3: send it to user (in pre-updated state),
4: update found document,
2: save a reference (of the current updated doc)
With findOneAndUpdate I can do all, but not saving a current reference.
So, how I need to approach it then?
Like this;
Room.findOne({ Roomid: roomid }, function (err, oldRoom) {
//make changes to oldRoom
//then save it like this
oldRoom.save(function(err,newRoom) {
//newRoom is updated document
//now you have reference to both old and new docs
});
})
In the end of the road i found out that i was trying to make it wrong. The idea of storing reference (instance) of doc, accessed by different users is obviously bad, as it leads to data conflicts between those instances. Also, approach with separate find and save can cause racing conditions and conflics as being non atomic operation, its far better to use findOneAnd*** to make mongoose\mongoDB handle db requests querieng by itself and make sure that no conflicts will occure.

In socket.io, how do I differentiate between 2 triggers of the same event?

Suppose I have a simple event defined as
socket.on('event', function(data){
...
});
And if the client fires it two times, one after another
socket.emit('event'); //once
socket.emit('event'); //again
Is there a way to *inherently** differentiate between the two events?
*I don't want want to depend on data because that's just a client side variable, and could easily be tampered with. (right?)
For context, it's related to this question.
I would use sessionSockets to save data for each user on the server side.
sessionSockets.on('connection', function (err, socket, session) {
socket.on('event', function() {
if(!session.eventReceived) {
// manage event
// save event received in session
session.eventReceived = true;
session.save();
}
});
});

How to handle Node/MongoDB connection management?

I'm using the node-mongodb-native to connect to a local MongoDB instance. I'm having a little trouble wrapping my head around how to handle the connections. I've attempted to abstract the MongoDB stuff into a custom Database module:
Database.js
var mongo = require('mongodb');
var Database = function() { return this; };
Database.prototype.doStuff = function doStuff(callback) {
mongo.connect('mongodb://127.0.0.1:27017/testdb', function(err, conn) {
conn.collection('test', function(err, coll) {
coll.find({}, function(err, cursor) {
cursor.toArray(function(err, items) {
conn.close();
return callback(err, items);
});
});
});
});
};
// Testing
new Database().doStuff(function(err, items) {
console.log(err, items);
});
Is a new connection required for each method? That seems like it would get expensive awfully quick. I imagined that perhaps the connection would be established in the constructor and subsequent calls would leverage the existing connection.
This next question may be more of a design question, but considering how connection setup and tear-down may be expensive operations, I'm considering adding a Database object that is global to my application that can be leveraged to make calls to the database. Does this seem reasonable?
Please note that the code above was roughly taken from here. Thanks for your help.
You don't need a new connection for each method - you can open it once and use it for subsequent calls. The same applies to the individual collection variables - you can cache the result of a single call to collection() and this will let you only need those callbacks once, leaving them out everywhere else.

Resources