I'd like to create a model to handle everything related to users, starting with a findOne() function.
app.js:
var u = new User(client);
u.findOne(function(error, user) {
console.log(error, user);
});
models/User.js:
var User = function (client) {
this.client = client
};
User.prototype.findOne = function (id, callback) {
client.connect();
client.get('testkey', function(error, result) {
var test = "hello#world.com";
callback(null, test);
client.close();
});
};
module.exports = User;
node.js complains findOne() would be undefined.
What's the correct way of creating such models and providing them with objects, like database pools etc.?
Your code contains various errors:
You do not use new when creating the instance
You mixed a function with the object literal syntax:
var User = function (client) {
client: client
};
You want this.client = client; instead. Right now the function body does nothing as it just defines a label called client does nothing with the variable client.
I would suggest you to search for an existing ORM for node.js instead of trying to write one on your own.
Related
After receive message from client, I have to connect db(mysql) and save data and need to response the result to client and inform to other(admin) client.
So I need to get current socket client and special client(admin) from the socket list.
Is it possible to get current socket outside of wss connection block?
Thanks.
const WebSocketServer = require('ws');
// Creating a new websocket server
const wss = new WebSocketServer.Server({ port: 8080 });
const clients = new Map();
// Creating connection using websocket
wss.on("connection", ws => {
console.log("new client connected");
client_id = Date.now();
clients.set(client_id, ws);
// sending message
ws.on('message', function(message) {
//wss.broadcast(JSON.stringify(message));
console.log('Received: ' + message);
BuyCoin(message);
//console.log()
});
ws.on("close", () => {
console.log("the client has connected");
});
ws.onerror = function () {
console.log("Some Error occurred")
}
// ws.send('You successfully connected to the websocket.');
});
function BuyCoin(strValue){
const req_info = JSON.parse(strValue);
console.log(req_info.user_id)
console.log('betting!');
var sql = 'SELECT * from users where id = ? LIMIT 1'
connection.query(sql, req_info.user_id, (ws)=>{
return function(err, rows, fields) {
//console.log("ix="+ix);
ws.send(rows[0]);
};
});
}
}
You have several options:
#1: You can put the BuyCoin function logic inside the ws scope to make it a local function that is in scope of the ws variable for the current connection like this:
const WebSocketServer = require('ws');
// Creating a new websocket server
const wss = new WebSocketServer.Server({ port: 8080 });
const clients = new Map();
// Creating connection using websocket
wss.on("connection", ws => {
console.log("new client connected");
client_id = Date.now();
clients.set(client_id, ws);
// sending message
function BuyCoin(strValue) {
const req_info = JSON.parse(strValue);
console.log(req_info.user_id)
console.log('betting!');
var sql = 'SELECT * from users where id = ? LIMIT 1'
connection.query(sql, req_info.user_id, (ws) => {
return function(err, rows, fields) {
//console.log("ix="+ix);
ws.send(rows[0]);
};
});
}
ws.on('message', function(message) {
//wss.broadcast(JSON.stringify(message));
console.log('Received: ' + message);
BuyCoin(message);
//console.log()
});
ws.on("close", () => {
console.log("the client has connected");
});
ws.onerror = function() {
console.log("Some Error occurred")
}
// ws.send('You successfully connected to the websocket.');
});
#2: You can pass the ws value to your BuyCoin() function as an argument by just changing the function call from this:
BuyCoin(message);
to this:
BuyCoin(ws, message);
And, then changing your function declaration from this:
function BuyCoin(strValue) {...}
to this:
function BuyCoin(ws, strValue) {...}
Is it possible to get current socket outside of wss connection block?
No, there really is no such thing as the current socket. When using asynchronous code in nodejs, lots of different pieces of code can be "in-flight" at the same time so there is no global sense of the current socket. Instead, you have manage data specific to your current operation either by using scope, by passing as an argument or by setting as a properties on some other object that is passed as an argument. Since there is no natural object that BuyCoin() already has access to here that is specific to the user with the activity, then that leaves the first two options (using scope and passing as an argument).
FYI, this code looks a bit problematic because you're allowing the webSocket to send in the user_id that will be operated on without any visible authentication. That exposes you to rogue sockets that can pretend to be users that they aren't.
Also, it doesn't appear you have code that removes webSockets from the clients Map object when they disconnect so that Map object will just get larger and larger and contain lots of dead connections.
Another thing that needs fixing is that your connection.query() code is declaring a callback that does nothing but return another function and it tried to make up a value of ws that would never actually be passed. That function you create inside the callback is never called. Change from this:
connection.query(sql, req_info.user_id, (ws) => {
return function(err, rows, fields) {
//console.log("ix="+ix);
ws.send(rows[0]);
};
});
to this:
connection.query(sql, req_info.user_id, (err, rows, fields) => {
//console.log("ix="+ix);
ws.send(rows[0]);
});
And, combine that with one of the above two solutions to get access to the ws value.
I have a bit of an issue with the asynchronous implementation of the MongoDB driver for Node.js.
In the documentation examples, connection takes place as follows:
const client = new MongoClient(uri, ...);
async function run() {
try {
await client.connect();
const coll = client.db('locations').collection('streets');
coll.find({...});
} catch {
...
} finally {
client.close();
}
}
run().catch(console.dir);
But let's say I want to use the connection in an object rather than create a function for every case when I need the connection. For example, I want to create an object which would allow me to insert comments into a database:
const Comments = {
connection: /* how would I put a MongoDB connection here when it's async? */,
commentsCollectionRef: /* how would I put a collection reference here? */
add: function(user, comment) {
collectionRef.insertOne({user, comment});
}
};
/* And to use the object like this to insert comments: */
Comment.add("Martin", "hello");
Comment.add("Julie", "hi");
Comment.add("Mary", "hello");
Presumably, it is impossible to do something like this:
async function connect() {
await client.connect();
}
const Comments = {
connection: connect() /* this returns a promise, but you can't store a reference to its value like this */
...
}
Is having a function which connects each time and closes the connection each time really the only option with MongoDB?
Thank you
You don't have to open a new connection every time you call the database. You can simply keep a separate variable with the status of the connection.
Something like:
const client = new MongoClient(uri, ...);
let connected = false;
async function connnect() {
if(!connected) {
await client.connect();
connected = true;
}
}
async function disconnect() {
if(connected) {
await client.close();
connected = false;
}
}
// All other comment specific code next...
Then you can build your library around this.
For each of your methods that interact with the database, call connect first.
Or simply call connect when you boot up the app and disconnect when you exit.
However, if you're going to have objects that represent database collections I would recommend having a look at Mongoose. You can easily define models and it can make your life a bit easier.
I would like to reuse a RabbitMQ channel in different node modules. Since the channel is created asynchronously, I am not sure what the best approach would be to "inject" this channel object to other modules.
If possible, I would like to avoid external dependencies like DI containers for this.
Below, you find my simplified code.
Thank you in advance for any advice.
web.js
require('./rabbitmq')(function (err, conn) {
...
// Start web server
var http = require('./http');
var serverInstance = http.listen(process.env.PORT || 8000, function () {
var host = serverInstance.address().address;
var port = serverInstance.address().port;
});
});
rabbitmq.js:
module.exports = function (done) {
...
amqp.connect(rabbitMQUri, function (err, conn) {
...
conn.createChannel(function(err, ch) {
...
// I would like to reuse ch in other modules
});
});
}
someController.js
module.exports.post = function (req, res) {
// Reuse/inject "ch" here, so I can send messages
}
you could always attach your channel handle to global object and it can be accessed across module:
// rabbitmq.js
global.ch = ch
// someController.js
global.ch // <- is the channel instance
I would prefer to inject the handle into each function because i think it is more explicit and easier to reason about and unittest. You could do that with partial function application
with lodash:
var post = function (req, res, rabbitMQchannel) {
// Reuse/inject "ch" here, so I can send messages
}
var ch = getYourChannel();
// post is function object that accepts two params, and the
// third is bound to your channel
module.exports.post = _.partialRight(post, ch);
a third option is to have rabbitmq.js export a function to getting a channel. A channel could be a singleton so there would only ever be one instance of it. Then any method that whats a channel handle would request one from the method, which wouldn't require channels to be passed around through functions, or globally.
I'm currectly creating an app using Node.JS that makes use of Express and Socket.io. As time progresses it's becoming increasingly difficult to deal with one file, I'm in the process of moving certain things out that I know how but was wondering on the best approach to do this.
I have a private area constructor similar to:
privateArea.js
function privateArea(props) {
this.id = props.id;
this.name = props.name;
this.users = [];
}
privateArea.prototype.addUser = function(socketId) {
this.users.push(socketId);
};
module.exports = privateArea;
I'd like to have this also have access to the socket.io variable that's been setup for use in a separate sockets.js file that can be included via the main app.js and a seperate file for express.js
So I'd like the structure as follows:
project
| app.js - joins it all together
| express.js - initialises and manages all express routing
| privateArea.js - constructor for private areas - must be able to reference socket.io
| sockets.js - initialises and manages all socket.io sockets and events
Any help/examples would be very appreciated.
Thanks
I use socket.io and express quite often in my projects, and I've developed a template which makes things easy. I like to have a fail-over in case the socket connections drops for some reason, or if a socket connection cannot be established. So I create http channels as well as socket channels. Here's a basic module template:
module.exports = function () {
var exported = {};
var someFunction = function (done) {
//.. code here..//
if (typeof done === "function") {
done(null, true);
}
};
// export the function
exported.someFunction = someFunction;
var apicalls = function (app) {
app.get("/module/someFunction", function (req, res) {
res.header("Content-Type", "application/json");
someFunction(function (err, response) {
if (err) return res.send(JSON.stringify(err));
res.send(JSON.stringify(response));
});
});
};
exported.apicalls = apicalls;
var socketcalls = function (io) {
io.on("connection", function (socket) {
socket.on('module-someFunction', function () {
someFunction(function (err, response) {
if (err) return socket.emit('module-someFunction', err);
socket.emit('module-someFunction', response);
});
});
});
};
exported.socketcalls = socketcalls;
return exported;
}
So to use this, I'd first need to include the module in my app.js file like this:
var mymod = require('./myModule.js');
And then I can enable access to this service from HTTP and over the websocket like this:
mymod.apicalls(app); // passing express to the module
mymod.socketcalls(io); // passing socket.io to the module
Finally, from the front-end, I can check to see if I have a socket connection, and if so, I use the socket to emit "module-someFunction". If I don't have a socket connection, the front-end will do an AJAX call instead to "/module/someFunction" which will hit the same function on the server side that it would've had I used the socket connection.
As an added bonus, if I need to utilize the function within the server, I could do that as well since the function is exported. That would look like this:
mymod.someFunction(function (err, response) {
// ... handle result here ... //
});
I am new to JS and I have a simple question. I am writing a node_redis code to connect to the db.
I have created a db module in which there is an init function to start the connection.
the module also has another function which queries the db. for the query, i will need the connection (dbConnection) object from the first function and then use it in the 2nd function. how do i do this? I can get it done by using global variables but most places tell me its a bad idea.
Sorry if the question is stupid, I am learning how to code. results in google tell me that it can be done by passing it as an object property. But i don't know if it is the proper way to do things in my context, or even how to do it.
var redis = require('redis');
module.exports = redisDb = {
// Initialize the module. Invokes callback when ready (or on error)
init: function(config, callback) {
// Open the database connection
var dbConnection = redis.createClient(config.db.port, config.db.host, {no_ready_check: true});
dbConnection.auth(config.db.authKey, function() {
console.log("Connected!");
console.log(dbConnection.keys('*'));
});
dbConnection.on('connect' , log('connect'));
dbConnection.on('ready' , log('ready'));
dbConnection.on('reconnecting', log('reconnecting'));
dbConnection.on('error' , log('error'));
dbConnection.on('idle' , log('idle...'));
dbConnection.on('end' , log('end'));
function log(type) {
return function() {
console.log(type, arguments);
}
}
callback("callback - Connected");
},
getValue: function(key, callback) {
dbConnection.hgetall("hosts", function (err, obj) {
console.dir(obj);
});
}
};
EDIT:
tried another way. still failing.
module.exports = redisDb = (function() {
var config = require('../config');
var redis = require('redis');
return {
connection: function(config) {
var dbConnection = redis.createClient(config.db.port, config.db.host, {no_ready_check: true});
dbConnection.auth(config.db.authKey, function() {
console.log("Authenticated!");
});
return dbConnection
},
getValue: function(connection, callback) {
connection.hgetall("hosts", function (err, obj) {
console.dir(obj);
});
}
}
})();
Now one way is as you said to make dbConnection an object Property.
The other way is to call init() in getValue() which results in establishing different connection every time you want some value.
Because a DB Connection is a valuable resource, I'd say it's better to use the second variant.
Of course then you'll need to return dbConnection from init().
PS: Global variables were made initially for such things and then people saw that fewer they are the better. That's why using global vars is considered a bad style.
I made the code work by simply declaring the connection in the parent function.
module.exports = _redisDb = (function() {
var redis = require('redis');
var config = require('../config');
var dbConnection = redis.createClient(config.db.port, config.db.host, {no_ready_check: true});
dbConnection.auth(config.db.authKey, function() {
console.log("Authenticated!");
});
var getValue = function() {
dbConnection.hgetall("hosts", function (err, obj) {
console.dir(obj);
});
}
return {
getValue: getValue
}
})();
While the above work,s I'd still like for someone to tell me how can I pass variables/objects between functions off the same module.