MongoDb Mongoose GridFs Problem Connecting After close - javascript

if i turn my backend on and call the getImage API It works fine.
But if I Call any other API before it. I get this error (uncaughtException: MongoNotConnectedError: Client must be connected before running operations)
I suspect this is because I'm closing the connection after each API in the Finally{} But I'm using the DbConnect() Function in the start of the GetImage Function Why is it not working properly?
It used to work before I started closing the Mongoose Connection after each API.
How can I make it work? and still close the Connection?
This Is The DbConnect Function
export async function dbConnect(): Promise<mongoose.Connection> {
if (cached.conn) {
return cached.conn
}
if (!cached.promise) {
const opts = {
bufferCommands: false,
useNewUrlParser: true
}
cached.promise = mongoose.connect(MONGODB_URI, opts).then((mongoose) => {
return mongoose
})
}
cached.conn = await cached.promise
return cached.conn
}
This is the Close Connection I'm using in the end of each api
export async function closeConnection() {
mongoose.connection.close();
}
And Lastly this is the api i'm using to get an image from GridFs
//This is the GetImage Function
apiRoute.get(async (req: NextApiRequest, res: NextApiResponse) => {
try {
await dbConnect();
if (!req.query.id) {
return res.status(400).json({ success: false, msg: "Bad Request" })
}
let gfs = new mongoose.mongo.GridFSBucket(mongoose.connection.db, { bucketName: "files" })
const readStream = gfs.openDownloadStream(new mongoose.mongo.ObjectId(String(req.query.id)));
readStream.pipe(res)
} catch (err) {
return res.status(500).json({ success: false })
}
});

Related

"mongoError: Topology was destroyed" when trying to delete/update a document

I am trying to make a discord bot from NodeJS that utilizes MongoDB for its database. When I try to delete or update a document, sometimes, it returns mongoError: Topology was destroyed. I have read up on this error before and it says that the connection was being interrupted.
Here is the code for my Database Handler:
class DatabaseHandler {
constructor(client) {
this.client = client;
}
async connect(callback) {
try {
await this.client.connect();
await callback(this.client);
} catch (err) {
console.error(err);
} finally {
this.client.close();
console.log("CLIENT CLOSED");
}
}
}
module.exports = DatabaseHandler;
Here is the place that the error occurs:
DB.connect(async (client) => {
console.log(ObjectId(this._id));
let DBList = await client.db("Giveaways").collection("giveawayData");
let delVal = {
_id: ObjectId(this._id)
};
await DBList.deleteOne(delVal); // error occurs here
})
I do not think it is because of the this.client.close() because it is executed after all of the operations are finished.

My Node Script Hangs after functions are finished

I'm calling three functions, after the completion of these functions I want my script to close on it's own but it just hangs.
I've tried making the functions async/promise based, closing the database after each 'mongodb' type function, and using process.exit() within a function as a callback to the last called function.
Connecting to the (local - not Atlas) Database:
MongoClient.connect(local, {useNewUrlParser: true, useUnifiedTopology: true}, function(err, db) {
if (err) {
console.log(err)
}
else {
console.log('Connected to MongoDB...')
//Read in data from jsonfiles and store each file's contents into the database : This is where the functions are being called... within a successful connect to the MongoDB
insertJSON(db, jsonfiles, 'requests', jsonfilesSource)
insertJSON(db, issuedfiles, 'issuedLicenses', isssuedfilesSource)
insertLicenses(db)
}
db.close()
})
Function 1:
function insertJSON(db, dirBuf,collection, sourceFolder) {
var database = db.db('license-server')
var collection = database.collection(collection)
fs.readdir(dirBuf, function(err, files) {
if (err) {
console.log(err.message)
}
else {
files.forEach(function(filename) {
var text = fs.readFileSync(sourceFolder + filename);
var filecontents = JSON.parse(text)
//collection.insertOne(filecontents)
collection.findOne({"DisplayTitle" : filecontents.DisplayTitle, "NodeInformation" : filecontents.NodeInformation, "Date": filecontents.Date})
.then(function(result) {
if(result) {
console.log(`An Item could already be in the database: A file is unique if its display title, nodeinformation, and date are different.
the items display title is ${result.DisplayTitle}`)
return
}
else {
collection.insertOne(filecontents)
console.log(`Added ${filecontents.DisplayTitle} to database`)
}
})
.catch(function(error) {
console.log(error)
})
})
}
})
}
Function 2:
function insertLicenses(db) {
// Set up GridFS to import .lic and .licx files into the database
var database = db.db('license-server')
var collection = database.collection('fs.files')
var bucket = new mongodb.GridFSBucket(database);
var dirBuf = Buffer.from('../license-server/private/licenses')
fs.readdir(dirBuf, function(err, files) {
if (err) {
console.log(err.message)
}
else {
files.forEach(function(filename) {
collection.findOne({"filename": filename}).
then(function(result) {
if(result) {
console.log(`The file ${filename} is already in the database`)
return
}
else {
fs.createReadStream('./private/licenses/' + filename).
pipe(bucket.openUploadStream(filename)).
on('error', function(error) {
assert.ifError(error)
}).
on('finish', function() {
console.log(`Uploaded ${filename}`)
})
}
})
})
}
})
// I tried calling db.close() here since this is the last function to be called. No luck.
}
I'm guessing it has something to do with the mongodb functions having their own way to close themselves but I couldn't seem to find what I was looking for in previous attempts to resolve this issue.
The expected result should be the script closing itself, the actual result is a handing script.
All of these database calls are asynchronous -- the result of this code running is to immediately call db.close and then do the work in insertJSON and insertLicenses. If you were to rewrite this to use async/await (and you'd need to update your other functions as well) the db.close call would close the db, and that would allow the script to exit:
await insertJSON(db, jsonfiles, 'requests', jsonfilesSource)
await insertJSON(db, issuedfiles, 'issuedLicenses', isssuedfilesSource)
await insertLicenses(db)
db.close()
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Introducing
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

Error: Node.js module defined by file index.js is expected to export function named xxxx

Hello there dev community. I´m trying to debug a firebase function and being trying using several tutorials, but with no success...
I´ve tried
(https://medium.com/#mwebler/debugging-firebase-functions-with-vs-code-3afab528bb36)
(https://medium.com/#david_mccoy/build-and-debug-firebase-functions-in-vscode-73efb76166cf)
My purpose is to get google contacts.
functions/index.js
const { google } = require('googleapis');
const oauthUserCredential = require('./oauthUserCredential.json')
const OAuth2 = google.auth.OAuth2
const key = require('./serviceAccountKey.json')
const jwt = new google.auth.JWT(key.client_email, null, key.private_key, 'https://www.googleapis.com/auth/contacts')
exports.getGoogleContacts = functions.https.onCall(async (data, context) => {
const requestingUser = data.requestingUser
console.log('getGoogleContacts-requestingUser', requestingUser)
const oauth2Client = new google.auth.OAuth2(
'client_id',
'client_secret',
'http://localhost:5000/xxx-xxx/us-central1/OAuthCallbackUrl'
);
const contacts = google.people({
version: 'v1',
auth: oauth2Client,
});
console.log('contacts ?', contacts)
(async () => {
const { data: groups } = await contacts.people.get({
resourceName: 'contactGroups',
});
console.log('Contact Groups:\n', groups);
})()
jwt.authorize((err, response) => {
console.log('inside authorize')
if (err) {
console.error(err);
response.end();
return;
}
// Make an authorized request to list contacts.
contacts.people.connections.list({
auth: authClient,
resourceName: 'people/me'
}, function (err, resp) {
if (err) {
console.error(err);
response.end();
return;
}
console.log("Success");
console.log(resp);
response.send(resp);
});
});
// this is another approach I´ve tried, but it´s also not working
const oAuth2Client = new OAuth2(
oauthUserCredential.web.client_id,
oauthUserCredential.web.client_secret,
oauthUserCredential.web.redirect_uris,
)
oAuth2Client.setCredentials({
refresh_token: oauthUserCredential.refresh_token
})
return new Promise((resolve, reject) => {
console.log('[INSIDE PEOPLE CONNECTIONS]')
contacts.people.connections.list({
auth: oauth2Client //authetication object generated in step-3
}, function (err, response) {
if (err) {
console.log('contacts.people.connections error')
console.log(err)
reject(new Error(err))
} else if (response) {
console.log('contacts.people.connections response')
console.log(response)
resolve(response)
}
});
})
.then(result => { return { found: result } })
.catch(err => { return { error: err } })
})
I´ve tried several different approachs and followed different tutorials
(Using Google People API with Cloud Functions for Firebase)
(https://flaviocopes.com/google-api-authentication/)
(https://medium.com/#smccartney09/integrating-firebase-cloud-functions-with-google-calendar-api-9a5ac042e869)
(https://cloud.google.com/community/tutorials/cloud-functions-oauth-gmail)
but none of them show clearly how could I get my contacts list.
I was able to use a client side code by following this tutorial (https://labs.magnet.me/nerds/2015/05/11/importing-google-contacts-with-javascript.html)
but I thought that living the client_id, client_secret and apiKey exposed in the client side would be a security problem...
I´m submitting also a tutorial request to make it very clear how to get contacts list from google account using firebase functions.
The Error you are receiving is because the cloud function cannot find the function named xxxx to execute, as you have not defined any function named xxxx in the index.js file.
Your Cloud Function to execute name, according to the error message is xxxx but the function that you are calling in index.js is getGoogleContacts. Please make sure that these names are the same, for example change getGoogleContacts to xxxx or change function to execute to getGoogleContacts

How to wait for async data before send response using promises and arrow functions?

I'm new to ES6, arrow functions and promises, and I can't figure out how to use them, even worse together.
I started a project with a REST generator (https://github.com/diegohaz/rest) and it works fine, but I need to modify part of the authentication.
I need to return data from a third-party server during authentication. I created the function that returns the data correctly with axios, however I can't return this information along with the other information (from this project), response is sent before.
Below is the generated code, almost untouchable, I added just extraData: user.getExtraData(user)
// function in auth controller file
export const login = ({ user }, res, next) => {
sign(user.id)
.then((token) => ({
token, user: user.view(true), extraData: user.getExtraData(user)
}))
.then(success(res, 201))
.catch(next)
}
// function in user model file
view (full) {
let view = {}
let fields = ['id', 'name', 'picture']
if (full) {
fields = [...fields, 'email', 'createdAt']
}
fields.forEach((field) => {
view[field] = this[field]
})
return view
}
Here is my function added into the user model
getExtraData (userView) {
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
axios.post( userView.host, querystring.stringify( {
data1:userView.data1,
data2:userView.data2
}))
.then((response) => {
return response.data
})
.catch((error) => {
console.log('Error', error)
return null
})
}
How would the best way to make response wait until extraData is return from getExtraData function with the given code ? Thanks
You can use async/await. In that case, you need to await for getExtraData. For such reason, the anonymous function inside login and getExtraData both need to be declared as asynchronous functions:
// function in auth controller file
export const login = ({ user }, res, next) => {
sign(user.id)
.then(async (token) => ({
token,
user: user.view(true),
// Wait for getExtraData to finish using await
extraData: await user.getExtraData(user)
}))
.then(success(res, 201))
.catch(next)
}
async getExtraData (userView) {
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
try {
const response = await axios.post( userView.host, querystring.stringify( {
data1:userView.data1,
data2:userView.data2
}))
return response.data
}
catch (err){
return null
}
}

Call Magento SOAP inside Meteor method invoked by the client

I'm using zardak:soap package in Meteor to connect with Magento SOAP v2 API. I've created a file inside the 'server' folder where I create a soap connection on Meteor.startup. Then I run a ticker that invokes random soap method every 30sec just to keep the connection up.
let soapConnection;
Meteor.startup(() => {
soapConnection = createAPIConnection('http://magento.site.com/api/v2_soap/?wsdl=1', {username: 'user', apiKey: 'password'});
});
function createAPIConnection(url, credentials) {
try {
let client = Soap.createClient(url);
let loginResult = client.login(credentials);
let sessionId = loginResult.loginReturn.$value;
return {
conn: client,
sessionId: sessionId
};
} catch (e) {
if (e.error === 'soap-creation') {
console.log('SOAP Client creation failed');
}
return null;
}
}
function tick() {
try {
soapConnection.conn.catalogCategoryInfo({
sessionId: soapConnection.sessionId,
categoryId: 1
}, (err, result) => { });
} catch (e) { }
}
Then I have a Meteor method that is called from the client. When it is called, the soap method call fails and I'm getting a 'soap error' message in console.
Meteor.methods({
'createMagentoCustomer'(customer) {
try {
soapConnection.conn.customerCustomerCreate({
sessionId: soapConnection.sessionId,
customerData: customer
}, (err, res) => {
if (err)
console.log('soap error');
else
console.log(res);
});
} catch (e) {
console.log('SOAP Method <customerCustomerCreate> call failed');
}
},
});
So, the ticker works well with no problems, but when I try to call soap via Meteor method, it fails. Notice that the soapConnection method is not null and I do receive error in the soap method callback.
Any suggestions?
Meteor version 1.3.4.1

Categories

Resources