why i should commmented the code
await mongoose.connection.close()
to make it work ?
here is my code:
const { MongoClient } = require("mongodb");
const mongoose = require('mongoose');
require('dotenv').config();
async function main() {
const uri = process.env.MONGO_URL;
try {
// Connect to the MongoDB cluster
await mongoose.connect(uri)
.then(()=> console.log("connect Succes"))
.catch((err) => {console.error(err)});
await createListing();
} finally {
// Close the connection to the MongoDB cluster
await mongoose.connection.close()
console.log("connect Closed")
}
}
main().catch(console.error);
async function createListing() {
const piscSchema = new mongoose.Schema({
name: String,
date: { type: Date, default: Date.now },
pool: String,
point: Number,
isAdd:Boolean
});
const piscModel = mongoose.model('piscModel', piscSchema, 'PointPiscine');
var itemPisc = new piscModel({
date:"12.10.2022",
pool:"dsfs",
point: 70,
isAdd:false
});
itemPisc.save(function (err, res) {
if (err) console.error(err);
console.log(res)
});
console.log("fin function call")
}
when i am not commented the code that close the connection.
i got this message
it is strange because it is connected to my mongodb.
as you can see the console log:
connect Succes
fin function call
connect Closed
You are calling the following function using a callback
itemPisc.save(function (err, res) {
if (err) console.error(err);
console.log(res)
});
This way the code continues to run without waiting for the result of this operation. It will then close the database connection without waiting for the result of this save function, which leads to this error.
If you modify you function the following way, it should wait for the result and close the connection afterwards:
try {
console.log(await itemPisc.save());
} catch (err) {
console.log(err);
}
You see the function 'main' is asynchronous, all those async functions are called asynchronously. You can try calling it with .then and do everything else in that .then:
... All the previous code
main().then(()=> {
async function createListing() {
...
// All the other code
})
Please comment on this line await mongoose.connection.close() then try I hope work it perfectly!!
Related
I am following a tutorial to make a blog, and for the MongoDB connection in the server.js file, the instructor made a boiler connection function withDB. Operations and res are props of withDB function. In line 6, is operations a function passed a prop of the withDB functions?
Below is the withDB function.
const withDB = async (operations, res) => {
try {
const client = await MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true });
const db = client.db('my-blog');
await operations(db); // is operations a function that takes db as its props?
client.close();
} catch (error) {
res.status(500).json({ message: 'Error connecting to db', error });
}
}
Using withDB in a function
app.get('/api/articles/:name', async (req, res) => {
withDB(async (db) => {
const articleName = req.params.name;
const articleInfo = await db.collection('articles').findOne({ name: articleName })
res.status(200).json(articleInfo);
}, res);
})
yes actually operations is your callback function, you call it with db as param once you initialize your database connection.
Maybe you're not comfortable with ES6 arrow function syntax. you can find in Mdn doc a simple example with old regular function, and in your case it could be :
function findArticlesByName(articleName) {
return function(db) {
return db.collection('articles').findOne({ name:
articleName });
}
}
async function withDB(callback) {
try {
const client = await MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true });
const db = client.db('my-blog');
return callback(db);
} catch (error) {
throw new Error({ message: 'Error connecting to db', error });
} finally {
client?.close();
}
}
app.get('/api/articles/:name', async (req, res) => {
try {
const articleInfo = await withDB(findArticlesByName(req.params.name));
res.status(200).json(articleInfo);
} catch(error) {
res.status(500).json(error);
}
})
Conclusion, you could easily inline your callback function like in your example, but maybe it's more understandable that way.
Moreover, you should avoid to use a wrapper in order to create and close your db connection after each request, because it could occur some weird errors. Databases connections or any resource-intensive tasks should be shared as much as possible.
So a better solution is to create a specific class with the default implementation of your singleton, construct a single instance of your connection at the top of your app, pass the single instance into each module that needs it then close your connection just before exiting your app.
Hope it'll help.
I am building tests for my node/express controller methods and using #shelf/jest-mongodb. I am creating a document first, and then when I try to find that I have to run find twice from model in order to get the results. It should get the results in the first find instead.
test.js
const { Subscription } = require('../src/models/subscription.schemaModel'); // model
const {
createSubscription,
} = require('../src/controllers/subscription.controller');
const subData = {...};
beforeAll(async () => {
await mongoose.connect(
process.env.MONGO_URL,
{ useNewUrlParser: true, useUnifiedTopology: true },
(err) => {
if (err) {
console.error(err);
process.exit(1);
}
}
);
});
afterAll(async () => {
await mongoose.connection.close();
});
describe('creates a subscription ', () => {
it('can be created correctly', async () => {
const sub = await createSubscription(subData);
await Subscription.find(); // if I comment out this line, I would get 0 results.
const subs = await Subscription.find();
expect(subs[0].items[0].sku).toBe(233234);
});
});
subscription.controller.js
const Mongoose = require('mongoose');
const { Subscription } = require('../models/subscription.schemaModel');
const isTestEnv = process.env.NODE_ENV === 'test';
module.exports.createSubscription = async (data) => {
try {
let error = null;
const doc = new Subscription(data);
doc.accountId = Mongoose.Types.ObjectId(doc.accountId);
await doc.save(function (err) {
if (err) {
logger.error(`createSubscription saving ${err}`);
error = err;
}
});
if (!error) {
logger.info(
`Subscription created => id: ${doc._id} store: ${doc.store}`
);
return doc;
} else {
return error;
}
} catch (err) {
logger.error(`createSubscription ${err}`);
}
};
The schemaModel file essentially contains the schema and exports model. Everything seems to work fine if I would do all the operations in the test file (schema+model+controller module)which defeats the purpose of testing my modules but not if I am importing. In this case I would have to run find() twice to get the results.
I have been trying multiple things from what I could find from googling, but no luck! Any help or lead would be appreciated. Also let me know if you need any other details.
Thank you!!
The only problem that posted code contains is that Mongoose promise API is mixed with legacy callback API. It appears that save results in race condition that is has been circumvented by random delay that extra find provides.
Although Mongoose documentation mentions that methods unconditionally return promises, a common pattern for JavaScript APIs that support both promises and callbacks is to enable promise control flow by omitting callback argument, and vice versa. This is most likely what happens here.
A way to avoid race conditions in such cases is to stick to promise control flow, e.g.:
beforeAll(async () => {
try {
await mongoose.connect(
process.env.MONGO_URL,
{ useNewUrlParser: true, useUnifiedTopology: true },
)
} catch (err) {
console.error(err);
process.exit(1);
}
});
According to this, the proper way for handling errors during initial connection is this:
try {
await mongoose.connect('mongodb://localhost:27017/test', { useNewUrlParser: true });
} catch (error) {
handleError(error);
}
Unfortunately, this results in a SyntaxError:
await mongoose.connect(mongoConnectionString, { useNewUrlParser: true });
^^^^^^^
SyntaxError: Unexpected identifier
When I remove await, the code is executed without any issues. When I googled SyntaxError: Unexpected identifier with await, I found that this happens when await is used with a not async function. But this doesn't make any sense since Mongoose is using asnyc connect from version 5 on. Also, the following async code is working properly as well:
mongoose.connect(mongoConnectionString, {
useNewUrlParser: true
})
.then(() => console.log('MongoDB Connected'))
.catch(err => console.log(err));
});
The dependency in package.json:
"mongoose": "^5.6.0"
index.js:
const express = require('express');
const app = express();
const mongoose = require('mongoose');
const mongoConnectionString = `mongodb://${process.env.MONGO_DB_USER}:${process.env.MONGO_DB_PW}#mongodb4711:27017/visitor-ips`;
initialMongoConnect(mongoose, mongoConnectionString);
function initialMongoConnect(mongoose, mongoConnectionString) {
try {
await mongoose.connect(mongoConnectionString, { useNewUrlParser: true });
} catch (error) {
handleError(error, mongoose, mongoConnectionString);
}
console.log('Initial connect to MongoDB successful');
}
function handleError(error, mongoose, mongoConnectionString) {
console.log('Error on initial connection: ' + error);
// wait 3 seconds and try to do the initial connect again
setTimeout(function() {initialMongoConnect(mongoose, mongoConnectionString)}, 3000);
}
So what's the issue with await here?
mongoose async operations, it supports promise runs async by default it doesn't need to await function because it is async when its success used then (()=>"what should do when it connection ) if it error use catch(()=>"what happened when the error happened ) and you should use keyword to used await that is async in start the function that wants to run as async function example
const a=async function(){
await ///what it is await the need to domming
I have created a mongodb native connection and saved it and then using findOne to query a document.
const Promise = require("bluebird");
const MongoClient = require('mongodb').MongoClient;
let mongoDB = undefined;
const getCollection = (collName) => {
if (mongoDB) {
return Promise.resolve(mongoDB.collection(collName));
} else {
return MongoClient.connect(EXT_CONFS.MONGODB_URL)
.then(db => {
mongoDB = db;
return Promise.resolve(mongoDB.collection(collName));
}).catch(e => {
console.error('Error in MongoDb connection');
});
}
};
const findOne = (collName, filter, options) => {
return getCollection(collName)
.then(collection => {
return collection.findOne(filter, options);
})
.then(doc => {
return Promise.resolve(doc);
}).catch(e => {
console.error(e);
return Promise.reject(e);
});
};
Now this all works fine, but if Mongo ShutsDown / Fails after db client is cached, There is no way to handle error. Error never goes to any catch handler :
console.error('Error in MongoDb connection');
or
console.error(e);
I even tried events :
mongoDB.on('connecting', function () {
console.log('connecting');
});
mongoDB.on('timeout', function (error) {
console.log('timeout!');
});
mongoDB.on('close', function (error) {
console.log('close!');
});
mongoDB.on('error', function (error) {
console.error('Error in MongoDb connection: ' + error);
});
mongoDB.on('connected', function () {
console.log('connected!');
});
mongoDB.on('connection', function () {
console.log('connected!');
});
mongoDB.on('connect', function () {
console.log('connected!');
});
mongoDB.once('open', function () {
console.log('connection open');
});
mongoDB.on('reconnected', function () {
console.log('reconnected');
});
mongoDB.on('disconnected', function () {
console.log('disconnected');
});
but no success still. Using NodeJS 4.5.0, MongoDB-Native driver 2.2.24
You should do something like console.error('Failed to connect to mongodb ',e); you are not outputting the error.
Also some events provide an additional parameter and you are outputting those either. In case of failing to connect to an mongodb server, your application should just notify you it's not the best approach to handle mongodb server start/restart from your application use daemons such as systemd or other process monitoring.
Some events are there to just notify the application that connection was lost or an reconnection is attempted, its up to you to handle what is going to be done when those events are emitted.
You can for example attempt to check mongodb status when an disconnect event is emitted an recreate connection object.
You could wrap the connect statement in a try-catch block.
I have the following code where I open a new mongoose connection to insert records, however when I try to close the connection after the forEach (which is supposed to be blocking) then it executes the mongoose.connection.close() inmediatly and doesn't insert any records on the database. Any ideas of how to do this?
Here is my code
'use strict';
const mongoose = require('mongoose');
const xlsx = require('node-xlsx');
const Model = require('./model');
mongoose.connect('mongodb://localhost:27017/exel', (err) => {
if (err) throw err;
});
let obj = xlsx.parse(file);
obj[0].data.forEach((item, index) => {
let newItem = {
nombre: item[2],
localidad: item[7],
cargo: item[8]
}
Model.create(newItem)
.then((createdItem) => {
console.log(createdItem);
})
.catch((err) => {
console.log(err);
});
});
mongoose.connection.close();
I tried creating a function with the forEach code inside it and adding the mongoose.connection.close() as a callback, using promises, using async and a few others but nothing works.
You can use async for this.
For example:
async = require("async");
async.each(items, function(item, callback){
// Call an asynchronous function, often a save() to DB
item.someAsyncCall(function (){
// Async call is done, alert via callback
callback();
});
},
// 3rd param is the function to call when everything's done
function(err){
// All tasks are done now
doSomethingOnceAllAreDone();
}
);