A possible timeout in find() method - mongoDb - node.js

I'm writing a Node.js project using MongoDb and socket.io. I met one problem. I have a collection called rooms rooms = db.collection('rooms');
Here's my code when i'm trying to join a room
rooms.find({name: roomName}).limit(1).toArray()
.then(function (res) { //if successful
res = res[0]; //i get my username
If there's a room with the given id I connect to it, otherwise it must be created.
But when i create a new room i get undefined, but when I connect the second time (the room already exists) it's all ok, i get all the information. So when I create a room and connect to it, I don't get my username, but when it's created (I'm connecting to it the second time) it displays me the method.
var mongo = require('mongodb').MongoClient - module,
function http(io) { mongo.connect(config.mongodb_url)
.then(function (db) { ...
-connection,
"mongodb version": "^2.1.7"
This is how i create a room
rooms.findOneAndUpdate(
{name: roomName},
{$addToSet: {users: uuid}}
).then(users_update).catch(logger.error);
}).catch(logger.error);
I'm wondering if there are some timeout in the find method? Or where can be here the mistake?

I found the answer. It was just that simple: I added { upstream: true } to my findOneAndUpdate() function.

Related

i want to connect db dynamically when user login nodejs mongodb

please help me to get out of it.
with login api i want to set mongoose connection string.
is it possible that with login api i set connection string and it works for other api also(which will call after login api)??
like first user login at that time i set db and for further api call works for that db?
i had tried
How to connect multiple mongodb database dynamically using mongoose?
but in this solution in each api they specifies requested param.
Can we set connection string of mongo by api call?
this is my app.js
var mongoose = require('mongoose');
var connections = [test = mongoose.createConnection('mongodb://localhost:27017/test'),
demo = mongoose.createConnection('mongodb://localhost:27017/demo')];
exports.getDatabaseConnection = function (dbName) {
if (connections[dbName]) {
//database connection already exist. Return connection object
return connections['dbName'];
} else {
connections[dbName] = mongoose.createConnection('mongodb://localhost:27017/' + dbName);
return connections['dbName'];
}
}
and this is my user.js
exports.authenticate = function (req, res) {
var db = app.getDatabaseConnection(req.body.keydb);
var userDetail = db.model('userdetail', UserSchema);
userDetail.findOne({
email: req.body.email,
userType: req.body.userType
}, function (err, user) {
if (err) throw err;
if (!user) {
res.send({ status: 400, message: req.i18n.__("user.authIncorrectEmail") });
} else {...}
});
}
when i am requesting keydb value as demo..then it should select demo string which is in connection array.
but it is not working.what i am doing wrong??
i am trying to connect mongoDb as per user login request comes. i want to set db once only not on each api call. if user logout then db should be disconnect and when again user login it should again connect.
You need to keep a list of database connections, one per session. One way to do it would be to have an object where the keys are the session IDs and the values are the database connections. Alternatively you can keep one connection per user ID if you want to allow a situation where the same user has multiple sessions and they each share the database connection. Now when you create a session on user login you also create a new database connection. When you destroy a session on user logout you have to close the connection and remove it from the object where it was stored. For all other endpoints except login and logout you just look up the connection and use it.
This is how you can achieve your goal but keep in mind that keeping a separate database connection per logged in user has many disadvantages and wastes a lot of resources, both in your application and in the database.
Can we set connection string of mongo by api call?
Yes, of course. But this will mean that people will be able to trick your app into e.g. breaking into other people's databases and you will be responsible for all of the legal consequences of that.

Possibility of writing to a wrong object with callback

I'm using a NodeJS Socket.IO server for handling realtime things. There is also an event in Socket.IO for authenticating a user. The code looks as follows:
var io = require('socket.io').listen(8080)
io.on('connection', function(socket) {
socket.on('auth', function(id) {
conn.query('SELECT id FROM u WHERE id = ?', id, function(e, result) {
socket.id = result[0].id
})
})
)}
My worries are about this line here:
socket.id = result[0].id
This is in a callback. When the DB executed the query.
So my question is: Is there a possibility that there can be wrong assignment with a lot of of connections at the same time? Seems that this happened already and data got assigned to the wrong socket object. Are there better methods for reliably do things like this?
The Socket object has a built-in field id. From http://socket.io/docs/server-api/#
strong textSocket#id:String
A unique identifier for the socket session, that comes from the
underlying Client.
Your code is trying to assign a different value to this built-in field, which seems like a bad idea. You should try to rename "your" id field to something else like authId or userId to avoid this conflict.

Node function runs multiple times inside Mongoose query

I'm creating an Agenda function (similar to a cron job) to email us a list of new users every night. I think maybe I don't understand how the data is returned from the Mongoose call as I seem to be getting duplicate emails by the same number of results are returned from the Mongoose query. (Postmark is an email api here)
Here's a trimmed down version of my code:
var Agenda = require('agenda');
var agenda = new Agenda({db: { address: 'mongodb://localhost/example }});
var User = mongoose.model('User', userSchema);
agenda.define('example email', function() {
User.find({ date: { $gt: date }}, function (err, users) {
if (err) // handle error
postmark.send({
// setup and send email with users listed in body
}, function(error, success) {
if (error) // handle error
console.log('Sent successfully');
});
});
// Run every day at 2am
agenda.every('* 2 * * *', 'example email');
agenda.start();
So firstly the email sends straight away as I run the server (this code is in app.js) - I'm not sure why that is. But the main issue is that I receive multiple emails - they were received exactly 10 minutes apart, whether that is of any relevance. So for example the DB query returned 4 users so I received 4 emails of exactly the same data.
Do I need to close the query or something? I'm not looping through labels before sending the email - I thought that model.find() would just return one array of labels? But seems to be returning the same data each time for every label in labels. Going mad here.
I've just tried it on my local machine and there isn't the same problem, but it's the exact same code. I've also checked the Agenda DB to make sure there isn't duplicate jobs.

Meteor cannot retrieve data from MongoDB

Pretty straightforward and without any sort of configuration ->
In the project directory I entered the command:
$ meteor mongo to access the mongodb
From there (mongo shell), I switched to db meteor using the command use meteor then entered some basic data to test:
j = { name: "mongo" }
k = { x: 3 }
db.testData.insert(j)
db.testData.insert(k)
I checked and got results by entering: db.testData.find()
Here's my meteor code provided that mongodb access is only required on the client:
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to test.";
};
Template.hello.events({
'click input' : function () {
// template data, if any, is available in 'this'
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
});
Documents = new Meteor.Collection('testData');
var document = Documents.find();
console.log(document);
var documentCbResults = Documents.find(function(err, items) {
console.log(err);
console.log(items);
});
}
Upon checking on the browser and based on the logs, it says undefined. I was unsuccessful from retrieving data from mongodb and showing to the client console.
What am I missing?
For this answer I'm going to assume this is a newly created project with autopublish still on.
As Christian pointed out, you need to define Documents on both the client and the server. You can easily accomplish this by just putting the collection definition at the top of the file or in another file which isn't in either of the server or client directories.
An example which prints the first two test documents could look like this:
Documents = new Meteor.Collection('testData');
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to apui.";
};
Template.hello.events({
'click input' : function () {
var documents = Documents.find().fetch();
console.log(documents[0]);
console.log(documents[1]);
}
});
}
Note the following:
The find function returns a cursor. This is often all you want when writing template code. However, in this case we need direct access to the documents to print them so I used fetch on the cursor. See the documentation for more details.
When you first start the client, the server will read the contents of the defined collections and sync all documents (if you have autopublish on) to the client's local minimongo database. I placed the find inside of the click event to hide that sync time. In your code, the find would have executed the instant the client started and the data probably would not have arrived in time.
Your method of inserting initial items into the database works (you don't need the use meteor by the way), however mongo will default to using an ObjectId instead of a string as the _id. There are subtle ways that this can be annoying in a meteor project, so my recommendation is to let meteor insert your data if at all possible. Here is some code that will ensure the testData collection has some documents:
if (Meteor.isServer) {
Meteor.startup(function() {
if (Documents.find().count() === 0) {
console.log('inserting test data');
Documents.insert({name: "mongo"});
Documents.insert({x: 3});
}
});
}
Note this will only execute if the collection has no documents in it. If you ever want to clear out the collection you can do so via the mongo console. Alternatively you can drop the whole database with:
$ meteor reset
It's not enough to only define collections on the client side. Your mongo db lives on the server and your client needs to get its data from somewhere. It doesn't get it directly from mongodb (I think), but gets it via syncing with the collections on the server.
Just define the Documents collection in the joint scope of client and server. You may also need to wait for the subscription to Documents to complete before you can expect content. So safer is:
Meteor.subscribe('testData', function() {
var document = Documents.find();
console.log(document);
});

How to get multiple socket attributes in socket.io?

I'm building a chat app on which, for every client connection, i need to set some attributes to every client instance using socket.io. When i save the attribute, i use:
client.set('name', name, function () {});
client.set('email', email, function () {});
....
and it runs fine.
When i need to get all the client properties, i have not found a better way than this:
client.get("name",function(err,name) {
client.get("email",function(err,email) {
.......
}
}
I need to nest all the "get" to asynchronously get data; but if i had 10 properties to get, do i need to nest all the 10 items? There must be a better way to do it, can anyone help me?
I don't attach attributes to the socket.
io.sockets.on('connection', function(socket) {
var username = "xx";
var email = "xx";
socket.on('doX', function(data) {
socket.emit('ackX', {username: username, email: email});
});
});
I don't know if it's the best solution, but I have seen many examples like that.
EDIT : socket.io - getting more than one field for a socket?
The correct answer may fit your needs

Resources