AzureFN - NodeJS program is not inserting rows into CosmosDB - javascript

I have the following Azure Function in NodeJS
which has as trigger: IoT Hub events.
And I need to transfer the messages to cosmos DB.
module.exports = function (context, IoTHubMessage) {
try {
var dbName = "db";
var collectionName = "encodedmessages";
context.log(`JavaScript eventhub trigger function called for message array: ${IoTHubMessage}`);
var mongoClient = require("mongodb").MongoClient;
context.log('MongoClient created');
mongoClient.connect("mongodb://xxx:password==#xxx.mongo.cosmos.azure.com:10255/?ssl=true&replicaSet=globaldb&retrywrites=false&maxIdleTimeMS=120000&appName=#db#",{useNewUrlParser: true, authSource: dbName}, function (err, client) {
if(err){
context.log(`Error occurred while connecting to DB ${err}`)
} else{
context.log('MongoClient connected to DB');
}
var collection = mongoClient.db(dbName).collection(collectionName);
context.log('MongoClient collection retreived');
collection.insertOne(IoTHubMessage, {w: 1});
//collection.insertOne({"testKey": 13.56}, {w: 1});
mongoClient.close();
context.log(`Saved message: ${IoTHubMessage}`);
context.done();
});
} catch (e){
context.log(`Error ${e}`);
}
context.log('Done called');
context.done();
};
I also have a console app sending messages to the iot hub running as explained here:
https://learn.microsoft.com/en-us/azure/iot-hub/quickstart-send-telemetry-dotnet
The output is the following:
2020-10-30T12:06:41.968 [Information] JavaScript eventhub trigger function called for message array: Test Message
2020-10-30T12:06:41.972 [Information] MongoClient created
2020-10-30T12:06:41.972 [Information] Done called
2020-10-30T12:06:42.026 [Information] Executed 'Functions.ProcessEncodedMessages' (Succeeded, Id=2fcb7fa8-b194-4499-bc39-775aef86aac0, Duration=24606ms)
I dont really understand why I dont see in the logs messages in this piece of code:
if(err){
context.log(Error occurred while connecting to DB ${err})
} else{
context.log('MongoClient connected to DB');
}
Its like if its never reaching to that point, and I dont get any error regarding the connection string either.

I believe the insertOne function returns a promise and you're not awaiting it hence its moving to the next statement which was mongoClient.close() thereby closing the connection.
You can re-factor your code to use ES8 async-await and post resolving the insertOne function's promise schedule the call to close the connection.
Here's a reference from the official docs.
const { MongoClient } = require("mongodb");
module.exports = function (context, IoTHubMessage) {
const dbName = "db";
const collectionName = "encodedmessages";
const connectionString = `mongodb://xxx:password==#xxx.mongo.cosmos.azure.com:10255/?ssl=true&replicaSet=globaldb&retrywrites=false&maxIdleTimeMS=120000&appName=#db#`;
const options = {
useNewUrlParser: true,
authSource: dbName
};
context.log(`JavaScript eventhub trigger function called for message array: ${IoTHubMessage}`);
const client = new MongoClient(connectionString, options);
try {
context.log('MongoClient created');
await client.connect();
const database = client.db(dbName);
const collection = database.collection(collectionName);
context.log('MongoClient collection retreived');
const insertResult = await collection.insertOne(IoTHubMessage, {w: 1});
context.log(`Saved message: ${IoTHubMessage}`, insertResult);
context.done();
context.log('Done called');
} catch (e){
context.log(`Error ${e}`);
context.done();
} finally {
client.close();
}
};

Related

MongoDB: Error “Cannot use a session that has ended” when inserting into a collection

Started using mongoDB today and used the sample code to first connect to a existing database and then add a new object into my collection:
//jshint esversion:6
const { MongoClient } = require("mongodb");
// Replace the uri string with your connection string.
const uri =
"mongodb://localhost:27017";
const client = new MongoClient(uri);
async function run() {
try {
const database = client.db('shopDB');
const products = database.collection('products');
// Query for a movie that has the title 'Back to the Future'
const query = { id: 1 };
const product = await products.findOne(query);
console.log(product);
//insert a new products
var newProduct = {id: 5, name: 'Cat', price: 10, stock: 0};
products.insertOne(newProduct, async function(err, res){
if (err) throw err;
console.log('1 product created');
})
} finally {
await client.close();
}
}
run().catch(console.dir);
If I execut the above code I get: Error “Cannot use a session that has ended” when inserting into a collection I assume it is because of the await client.close(); because if add this command to the callback func of my insertOne() func it works fine.
But if the command is in finally shouldn't the connection be terminated at the end of the function run()? Why is the session ended before I could insert my object?
Thank you for your help!
You are not awaiting for the insert and you code goes straight to finally to close the connection before the insert executes
await products.insertOne(newProduct)

mongo client: how can I reuse the client in separate file?

Here is db.js file
const client = new MongoClient(DATABASE, mongodbOptions);
const connectWithMongoDb = () => {
client.connect((err) => {
if (err) {
throw err;
} else {
console.log('db connected');
}
});
};
module.exports = { client, connectWithMongoDb };
I called the connectWithMongoDb function from my server.js. db connects successfully. but the problem is I can't reuse the client. for example, I want to make a separate directory for collections. (in order to get a collection I need client object)
So, here is my collection.js file
const { client } = require('../helpers/db-helper/db');
exports.collection = client.db('organicdb').collection('products');
but the problem arises as soon as this file(collection.js) is called.
I am getting this error:
throw new MongoError('MongoClient must be connected before calling MongoClient.prototype.db'
You have to get the connection after connecting to MongoDB post that you can use it anywhere.
Read - https://mongodb.github.io/node-mongodb-native/api-generated/mongoclient.html
let client;
async function connect() {
if (!client) {
client = await MongoClient.connect(DATABASE, mongodbOptions)
.catch(err => { console.log(err); });
}
return client;
}
conet getConectedClient = () => client;
const testConnection = connect()
.then((connection) => console.log(connection)); // call the function like this
module.exports = { connect, getConectedClient };

js doesnt execute extern function to recieve data from db

I'm trying to receive same version data from my MySQL (MariaDB) Server.
For better maintenance i created one connection Object to handle all database queries.
However when I query some data, it seems like it isn't executed in time, but later when the first await command appears.
dbControl.js :
var mysql = require('mysql');
function getConnection(){
let dbConnection = mysql.createConnection({
host: "localhost",
user: "root",
password: ""
});
dbConnection.connect(function (err) {
if (err) throw err;
});
this.get_version = function() {
let sql = 'SELECT * FROM versionControl ORDER BY id DESC LIMIT 1;'
dbConnection.query(sql, function (err, result) {
if (err) throw err;
console.log("vData:", result);
return result;
});
}
}
module.exports.getConnection = getConnection;
dataHandler.js:
const browserControl = require('./browserControl');
const dbControl = require('../db/dbControl');
const dbConnection = new dbControl.getConnection();
let versionData;
// Here it should be executed -->
versionData = dbConnection.get_version();
console.log(versionData);
async function get_something(){
// Here it is executed -->
const browser = await browserControl.startBrowser();
//......
}
There is a 3th file which simply controls the program. At the moment it just executes the function get_something() like:
const originData = require('./dataHandler.js');
let data = originData.get_something();
console.log(data);
P.s.: its all running with node, thanks in advance ;_)
Your get_something() is marked as async.
Call it with await get_something() or get_something().then(console.log).
Ok, I got a solution. The SQL query function returns a promise now and I created an extra "getVersion"-async-function which is waiting for the resolve of the promise. Thus the promise waits for the db answer and the rest waits until the promise is resolved.
the dataHandler.js now looks like this:
const browserControl = require('./browserControl');
const dbControl = require('../db/dbControl');
const dbConnection = new dbControl.getConnection();
async function getVersion() {
let versionData;
versionData = await dbConnection.get_version();
console.log(versionData);
}
getVersion();
async function get_something(){
const browser = await browserControl.startBrowser();
}
and the query-function now looks like this:
this.get_version = function() {
let sql = 'SELECT * FROM versionControl.lol_scraper ORDER BY id DESC LIMIT 1;'
return new Promise(resolve => {
dbConnection.query(sql, function (err, result) {
if (err) throw err;
console.log("vData:", result);
resolve(result);
})
});
P.s.: still open for smarter or more modern solutions ;_)

Node.js amqplib when to close connection

I am using amqplib to transfer messages in my node.js server. I saw an example from RabbitMQ official website:
var amqp = require('amqplib/callback_api');
amqp.connect('amqp://localhost', function(err, conn) {
conn.createChannel(function(err, ch) {
var q = 'hello';
var msg = 'Hello World!';
ch.assertQueue(q, {durable: false});
// Note: on Node 6 Buffer.from(msg) should be used
ch.sendToQueue(q, new Buffer(msg));
console.log(" [x] Sent %s", msg);
});
setTimeout(function() { conn.close(); process.exit(0) }, 500);
});
In this case, the connection is closed in an timeout function. I don't think this is a sustainable way to do it. However, ch.sendToQueue doesn't have a callback function allowing me to close connection after message is sent. What's a good point to close connection?
I'm using the promise API, but the process is the same. First you need to call channel.close() and then connection.close().
channel.sendToQueue() returns a boolean.
True when it's ready to accept more messages
False when you need to wait for the 'drain' event on channel before sending more messages.
This is my code using async/await:
async sendMsg(msg) {
const channel = await this.initChannel();
const sendResult = channel.sendToQueue(this.queue, Buffer.from(msg), {
persistent: true,
});
if (!sendResult) {
await new Promise((resolve) => channel.once('drain', () => resolve));
}
}
async close() {
if (this.channel) await this.channel.close();
await this.conn.close();
}

Node express app calling mssql is saying that Connection is closed

I have another app which uses express and routes but this new app i was slimming it down. I know the connection string stuff is correct
script.getQuestions(connection);
script.getQuestions = function(connection,req, res){
console.log(connection);
}
I have read that some people said online to change to use a promise for async fixes this... problem is that with my function having req and res i don't know how to pass those in when i even try to refactor with a promise
"ConnectionError: Connection is closed"
"(module.js:487:32) code: 'ECONNCLOSED', name: 'ConnectionError' }"
What I call up (script) is
var sql = require('mssql');
exports.getQuestions = function(connection, req,res){
console.log(connection);
var request = new sql.Request(connection);
var query = 'select * from Question'
request.query(query).then(function(resultset){
res.json(resultset.recordset);
}).catch(function(err){
console.log(err);
//res.json(err)
})
}
it's a bit hard to understand what you're doing there. But here is an promise example to use mssql
const sql = require('mssql')
sql.connect(config).then(pool => {
// Query
return pool.request()
.input('input_parameter', sql.Int, value)
.query('select * from mytable where id = #input_parameter')
}).then(result => {
console.dir(result)
// Stored procedure
return pool.request()
.input('input_parameter', sql.Int, value)
.output('output_parameter', sql.VarChar(50))
.execute('procedure_name')
}).then(result => {
console.dir(result)
}).catch(err => {
// ... error checks
})
sql.on('error', err => {
// ... error handler
})
source: https://www.npmjs.com/package/mssql#promises

Categories

Resources