Can't store response from EventEmitter to a database with NodeJS - javascript

I have this nodejs app which fetches feeds from some website.
The approach to fetch is through an event emitter since its connecting to a streaming API.
Anyway, the fetching works because I get the response log continuously from this:
console.log(JSON.stringify(feeds));
However it seems that storing the result to the database does not work. Although the store_feeds works.
I am not sure if the problem is with NodeJS or MongoDB, because if I create a loop to manually input JSON object to store_feeds, I can see that the db is updated.
Code for the event loop:
// Worker
var worker = setInterval(function(){
var q = "some query";
Feed.EventEmitter.once("feeds", function(feeds){
console.log(JSON.stringify(feeds));
store_feeds(JSON.stringify(feeds));
});
get_feeds(q);
console.log("\nWorker is running...\n");
}, 5000);
This is the code for storing feeds to MongoDB:
// Store
function store_feeds(feeds) {
var mongodb = require('mongodb');
var server = new mongodb.Server("IP_ADDRESS", 27017, {});
new mongodb.Db('test', server, {}).open(function (error, client) {
if (error) throw error;
var collection = new mongodb.Collection(client, 'feeds');
collection.insert(feeds, {safe:true},
function(err, objects) {
console.log("\nStoring Feed Results: " + feeds + "\n");
if (err) console.warn(err.message);
if (err && err.message.indexOf('E11000 ') !== -1) {
// this _id was already inserted in the database
}
});
});
}
This is code for the Event Emitter:
// Event Emitter
var Feed = (function(){
var eventEmitter = new events.EventEmitter();
return {
EventEmitter : eventEmitter, // The event broadcaster
latestFeed : 0 // The ID of the latest searched feed
};
})();

Related

how to reply and send message after receive message in node js using websocket

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.

How do I send information from a MQTT node into a MYSQL database?

I'm trying to recieve data from a MQTT node which I then want to proceed with putting into a MYSQL database. From what I've understood I need to use Javascript to do this, I however can't find any examples of this which will work. Is there anyone who have done this before who could help out? This specifically is about how to make a script in Javascript to send the information from the MQTT broker to a MYSQL database in node red. The question that was suggested as an answer is not specifically for Node Red nor does it offer any answers to my question about using Javascript as a way to achieve what I'm trying to do. The answer to that question was to use Node red but it was to no help with how you should use it.
yeah, you can use any language for sending payload from MQTT to MYSQL.
basically what you can do is set a small node which will subscribe to all the incoming payload and dump it in your MYSQL Db
here is the JS script:-
var mqtt = require('mqtt'); //https://www.npmjs.com/package/mqtt
var Topic = '#'; //subscribe to all topics
var Broker_URL = 'mqtt://MQTT_BROKER_URL';
var Database_URL = 'Database_URL';
var options = {
clientId: 'MyMQTT',
port: 1883,
keepalive : 60
};
var client = mqtt.connect(Broker_URL, options);
client.on('connect', mqtt_connect);
client.on('reconnect', mqtt_reconnect);
client.on('message', mqtt_messsageReceived);
client.on('close', mqtt_close);
function mqtt_connect() {
console.log("Connecting MQTT");
client.subscribe(Topic, mqtt_subscribe);
};
function mqtt_subscribe(err, granted) {
console.log("Subscribed to " + Topic);
if (err) {console.log(err);}
};
function mqtt_reconnect(err) {
console.log("Reconnect MQTT");
if (err) {console.log(err);}
client = mqtt.connect(Broker_URL, options);
};
function after_publish() {
//do nothing
};
//receive a message from MQTT broker
function mqtt_messsageReceived(topic, message, packet) {
var message_str = message.toString(); //convert byte array to string
console.log("message to string", message_str);
message_str = message_str.replace(/\n$/, ''); //remove new line
//message_str = message_str.toString().split("|");
console.log("message to params array",message_str);
//payload syntax: clientID,topic,message
if (message_str.length == 0) {
console.log("Invalid payload");
} else {
insert_message(topic, message_str, packet);
//console.log(message_arr);
}
};
function mqtt_close() {
//console.log("Close MQTT");
};
////////////////////////////////////////////////////
///////////////////// MYSQL ////////////////////////
////////////////////////////////////////////////////
var mysql = require('mysql'); //https://www.npmjs.com/package/mysql
//Create Connection
var connection = mysql.createConnection({
host: Database_URL,
user: "newuser", //DB Username
password: "mypassword", //DB Password
database: "mydb" //DB Name
});
connection.connect(function(err) {
if (err) throw err;
//console.log("Database Connected!");
});
//insert a row into the tbl_messages table
function insert_message(topic, message_str, packet) {
var message_arr = extract_string(message_str); //split a string into an array
var clientID= message_arr[0];
var message = message_arr[1];
var date= new Date();
var sql = "INSERT INTO ?? (??,??,??,??) VALUES (?,?,?,?)";
var params = ['tbl_messages', 'clientID', 'topic', 'message','date', clientID, topic, message, date];
sql = mysql.format(sql, params);
connection.query(sql, function (error, results) {
if (error) throw error;
console.log("Message added: " + message_str);
});
};
//split a string into an array of substrings
function extract_string(message_str) {
var message_arr = message_str.split(","); //convert to array
return message_arr;
};
//count number of delimiters in a string
var delimiter = ",";
function countInstances(message_str) {
var substrings = message_str.split(delimiter);
return substrings.length - 1;
};
Reference:-
https://github.com/karan6190/MQTT-DB-plugin/blob/master/mqttTOmysql.js
You can use any language to send messages from MQTT to MySQL database(or any other).
For example, you can create a separate python service which uses Paho MQTT client and subscribes to all the topics and adds that data to a database when the message is received.
Here is how the code will look like in Python:
def on_message(client, userdata, msg):
topic = msg.topic
payload = msg.payload
# run mysql query using library like MySQLdb
# https://www.tutorialspoint.com/python/python_database_access.htm
topic = '#" #subscribe to all topics
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.subscribe(topic)
client.connect(mqttserver)
client.loop_forever()

NodeJS Display live TCP data on dynamic routes

My ultimate goal is the following: my gardener has several devices that can send data to my Node.js server via TCP. This data is in JSON format, and looks something like the following:
Device A:
{"pagename": "spacekittens", "count": 11};
Device B:
{"pagename": "norwegiansultans", "count": 22};
As each of these are streamed to my server via TCP, I have added a ; to separate each stream. In addition, the count in each device stream is randomly generated.
Now, I want to add dynamic routes for each TCP packet that comes my way, and display content from that stream to that route.
So my route myserver:4000/spacekittens should show the following:
{"pagename": "spacekittens", "count": [random number every second]};
And my route myserver:4000/norwegiansultans should show:
{"pagename": "norwegiansultans", "count": [random number every second]};
In order to accomplish this I have set up the following code:
server.on("connection", function(socket) {
let chunk = "";
socket.on('data', function(data) {
chunk += data.toString(); // Add string on the end of the variable 'chunk'
let d_index = chunk.indexOf(';'); // Find the delimiter
// While loop to keep going until no delimiter can be found
while (d_index > -1) {
try {
let string = chunk.substring(0, d_index); // Create string up until the delimiter
// define local variables that can be used in a closure
let json = JSON.parse(string); // Parse the current string
let localData = data;
console.log(json.pagename); // Function that does something with the current chunk of valid json.
app.get("/" + json.pagename, function(req, res) {
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.write(JSON.stringify(json));
res.end();
});
} catch (e) {
console.log(e);
}
chunk = chunk.substring(d_index + 1); // Cuts off the processed chunk
d_index = chunk.indexOf(';'); // Find the new delimiter
}
});
socket.on("close", function() {
console.log("connection closed");
});
});
I appreciate any thoughts and comments on methodology with regards to what I am trying to accomplish. However, I did not post only for this reason. I have a problem.
Currently, my res.write() line only populates the data in my routes one time. Adding new data via sockets does not replace the content on my route.
So under the myserver:4000/spacekittens route my count shows 11, and even though I stream an updated number ("count": 12) my route myserver:4000/spacekittens still only shows 11. Console logging gives me the correct response each time data is sent. So I am not using the res.write() correctly since it does not override old data.
Unsure how to rectify.
I would seperate the pages data and route setup from the connection handling. You can't set the same route up every time you receive a JSON blob so this modifies the app route to return the data to the user. The data will change with each blob of JSON.
class Pages {
constructor(app){
this._store = {}
this.app = app
}
get( name ){
return this._store[name]
}
set( name, data ){
if ( !this.exists(name) ) this.setupRoute(name)
return this._store[name] = data
}
exists( name ){
return this._store.hasOwnProperty(name)
}
addJSON( json_string ){
let data = JSON.parse(json_string)
if ( !data.pagename ) throw new Error('No pagename in data: "%s"', json_string)
if ( !data.count ) throw new Error('No count in data "%s"', json_string)
return this.set(data.pagename, data)
}
setupRoute( name ){
let route = `/${name}`
this.app.get(route, (req, res)=>{
res.json(this.get(name))
})
console.log('setup route: %s', route)
return this.app
}
}
Then the connection handling just deals with pulling out the JSON strings for Pages.
const pages = new Pages(app)
server.on("connection", function(socket) {
let chunk = "";
socket.on('data', function(data) {
chunk += data.toString(); // Add string on the end of the variable 'chunk'
let d_index = chunk.indexOf(';'); // Find the delimiter
// While loop to keep going until no delimiter can be found
while (d_index > -1) {
try {
let string = chunk.substring(0, d_index); // Create string up until the delimiter
pages.addJSON(string)
} catch (e) {
console.error(e);
}
chunk = chunk.substring(d_index + 1); // Cuts off the processed chunk
d_index = chunk.indexOf(';'); // Find the new delimiter
}
});
socket.on("close", function() {
console.log("connection closed");
});
});
You could also use one of the line delimited JSON parsing libraries which will take a binary stream and emit the JSON out as plain objects:
ndjson or ld-jsonstream

how to store a mongodb array of collections inside an indexedDB

Hello I want to build a local database for my phonegap so user can use it offline.
I have this in angular function that creates a database.
function Database() {
return {
create: function (itemDocs) {
var db = null;
var request = indexedDB.open("myDB", 1);
request.onsuccess = function (event) {
db = event.target.result;
console.log("DB loaded successfully");
};
request.onerror = function (event) {
console.log(event)
};
request.onupgradeneeded = function (event) {
db = event.target.result;
console.log("DB initiliazed / created");
//create collections
db.createObjectStore("items", {keyPath: "_id"});
//create documents
var transaction = db.transaction(["items"], "readwrite");
var items = transaction.objectStore("items");
items.add(itemDocs);
};
}
}
}
The itemDocs holds a mongoDB collection (which is an array of objects) and I want to store that collection inside indexedDB database the problem im having is that I'm getting this annoying error.
Uncaught InvalidStateError: Failed to execute 'transaction' on 'IDBDatabase': A version change transaction is running.
Use var transaction = event.target.transaction instead of var transaction = db.transaction(...);
A full answer is rather lengthy. Briefly, you don't want to create a new transaction in onupgradeneeded. There is already an active transaction available for you.

How to create a user model with node.js?

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.

Categories