i am using nodejs as server, I am sending parameters to mongodb and saving it in database after that i am fetching it from database. But when i try to fetch the data i can't able to see the current data in nodejs terminal ,but it will be present in database. Again if i send the other data i will able to see the previous data but not the current data which i have sent now. I think my server is calling find function before save function. what should i do to make my save function to complete its task and then it should call the find function.
this mongodb code
import mongoose from 'mongoose';
var Schema = mongoose.Schema;
//connect to a MongoDB database
var db = mongoose.connect('mongodb://127.0.0.1:27017/student');
mongoose.connect('connected', function() {
console.log("database connected successfully")
});
var userSchema = new Schema({
Name: {
type: String,
required: true
},
Age: {
type: Number,
required: true
}
}, {
collection: ('studentcollection2')
});
var User = mongoose.model('User', userSchema);
function createStudent(name, age) {
var list = new User({
Name: name,
Age: age
});
list.save(function(err) {
if (err) throw err;
console.log("SUCCESSFUL");
});
}
function listStudent() {
User.find({}, function(err, studentcollection2) {
if (err) throw err;
console.log(studentcollection2);
});
}
exports.createStudent = createStudent; //module.exports = User;
exports.listStudent = listStudent;
this is my server code
import config from './config';
import express from 'express';
const server = express();
import mongodbInterface from './mongodbInterface';
server.set('view engine', 'ejs');
server.get('/', (req, res) => {
res.render('index', {
content: '...'
})
});
console.log(typeof mongodbInterface.createStudent);
mongodbInterface.createStudent("a9", 112);
mongodbInterface.listStudent();
server.use(express.static('public'));
server.listen(config.port, () => {
console.info('express listening on port', config.port);
});
I haven't run your code, but I imagine it's coming down to these two lines:
mongodbInterface.createStudent("a9", 112);
mongodbInterface.listStudent();
Both of these statements call asynchronous functionality. That is to say that when you call createStudent("a9", 112);, that functionality will run asynchronously in the background, and Node will continue to call listStudent(); straight away. Therefore, your createStudent method may not have written the data to the database by the time your listStudent function is run.
To solve this, you need to make use of callback functions to only retrieve the data once it's actually been saved. For example, you could do the following:
function createStudent(name, age, cb) {
var list = new User({
Name: name,
Age: age
});
list.save(function(err) {
if (err) return cb(err);
return cb();
});
}
function listStudent(cb) {
User.find({}, function(err, studentcollection2) {
if (err) return cb(err);
return cb(null, studentCollection2);
});
}
Then, in your server code:
mongodbInterface.createStudent("a9", 112, function(err) {
if (err) throw err;
mongodbInterface.listStudent(function(err, students) {
console.log(students); // You should see the newly saved student here
});
});
I'd recommend reading more about Node.js callbacks here - they are really core to the usage of Node.js.
The mongo methods are async so the data will write whenever it's ready. Use a callback function, promise or async/await to wait for the result without blocking the event loop and control order of execution.
Related
I am new to mongoDb, as I am trying to query from different collection and in order to do that, when I am fetching data from category collection I mean when I am running select * from collection it is throwing error, MongoError: pool destroyed.
As per my understanding it is because of some find({}) is creating a pool and that is being destroyed.
The code which I am using inside model is below,
const MongoClient = require('mongodb').MongoClient;
const dbConfig = require('../configurations/database.config.js');
export const getAllCategoriesApi = (req, res, next) => {
return new Promise((resolve, reject ) => {
let finalCategory = []
const client = new MongoClient(dbConfig.url, { useNewUrlParser: true });
client.connect(err => {
const collection = client.db(dbConfig.db).collection("categories");
debugger
if (err) throw err;
let query = { CAT_PARENT: { $eq: '0' } };
collection.find(query).toArray(function(err, data) {
if(err) return next(err);
finalCategory.push(data);
resolve(finalCategory);
// db.close();
});
client.close();
});
});
}
When my finding here is when I am using
let query = { CAT_PARENT: { $eq: '0' } };
collection.find(query).toArray(function(err, data) {})
When I am using find(query) it is returning data but with {} or $gte/gt it is throwing Pool error.
The code which I have written in controller is below,
import { getAllCategoriesListApi } from '../models/fetchAllCategory';
const redis = require("redis");
const client = redis.createClient(process.env.REDIS_PORT);
export const getAllCategoriesListData = (req, res, next, query) => {
// Try fetching the result from Redis first in case we have it cached
return client.get(`allstorescategory:${query}`, (err, result) => {
// If that key exist in Redis store
if (false) {
res.send(result)
} else {
// Key does not exist in Redis store
getAllCategoriesListApi(req, res, next).then( function ( data ) {
const responseJSON = data;
// Save the Wikipedia API response in Redis store
client.setex(`allstorescategory:${query}`, 3600, JSON.stringify({ source: 'Redis Cache', responseJSON }));
res.send(responseJSON)
}).catch(function (err) {
console.log(err)
})
}
});
}
Can any one tell me what mistake I am doing here. How I can fix pool issue.
Thanking you in advance.
I assume that toArray is asynchronous (i.e. it invokes the callback passed in as results become available, i.e. read from the network).
If this is true the client.close(); call is going to get executed prior to results having been read, hence likely yielding your error.
The close call needs to be done after you have finished iterating the results.
Separately from this, you should probably not be creating the client instance in the request handler like this. Client instances are expensive to create (they must talk to all of the servers in the deployment before they can actually perform queries) and generally should be created per running process rather than per request.
I am building a chatbot using WATSON API which sends artist data give users' input. I am trying to use nodejs promise in order to query my DB and print out the data, since DB accessing is asynchronous.
So the artpromise function is a function which takes in the artist's name and query the db to save the result in the 'result' variable. Then I am trying to print out the result (in chatbot i actually print out the result to the user).
However I am not getting the result I want and keep getting a syntax error. Any help would be appreciated.
let arttistinfo;
function artpromise (artist) {
return new Promise(function(resolve, reject) {
const MongoClient = require("mongodb").MongoClient;
const url = 'mongodb://majac.co.kr:27017/artbot';
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db("artbot");
var query = {name: artist};
artistinfo = dbo.collection("artistdb").find(query)
.toArray(function(err, result) {
if (err) throw reject(err);
resolve(result);
});
db.close();
}
});
)};
let artist = "Jan Tarasin";
artpormise.then(function(artist) {
console.log(result);
});
I'd rewrite like so, I can see there were a small number of issues with your code, but this works for me now:
function artpromise (artist) {
return new Promise(function(resolve, reject) {
const MongoClient = require("mongodb").MongoClient;
const url = 'mongodb://majac.co.kr:27017/artbot';
MongoClient.connect(url, function(err, db) {
if (err) throw err;
var dbo = db.db("artbot");
var query = {name: artist};
artistinfo = dbo.collection("artistdb").find(query)
.toArray(function(err, result) {
if (err) throw reject(err);
resolve(result);
});
db.close();
});
});
};
let artist = "Jan Tarasin";
artpromise(artist).then(function(result) {
console.log(result);
});
I get the result below:
[{
_id: 5abdbc18423795deaaff0d8e,
nationality: 'Polish',
art_link: 'https: //media.mutualart.com/Images/2016_06/29/20/203606422/0532d043-71f6-47bc-945e-aeededd2d483_570.Jpeg',
years: '1926',
name: 'JanTarasin',
art_title: '"Falujace watki I",
2003r.'
}]
MongoDB Node driver is natively supporting promises from v3 on. So you may greatly simplify your code by using them.
Here is how i would approach to your problem;
function artpromise (artist) {
const MongoClient = require("mongodb").MongoClient;
return MongoClient.connect('mongodb://majac.co.kr:27017') // connect to mongo server
.then(mc => mc.db('artbot') // get mongoClient object and connect to artbot db
.collection('artistdb') // connect to the artistdb collection
.find({name: artist}) // perform your query
.toArray() // convert the results into an array
.then(as => (mc.close(), as))) // close db and return array from query result
.catch(e => console.log(e)); // catch errors
}
let artist = "Jan Tarasin";
artpromise(artist).then(as => as.forEach(a => console.log(a)));
[nodemon] starting `node maeror.js`
{ _id: 5abdbc18423795deaaff0d8e,
nationality: 'Polish',
art_link: 'https://media.mutualart.com/Images/2016_06/29/20/203606422/0532d043-71f6-47bc-945e-aeededd2d483_570.Jpeg',
years: '1926',
name: 'Jan Tarasin',
art_title: ' "Falujące wątki I", 2003 r. ' }
[nodemon] clean exit - waiting for changes before restart
It might be useful to remind that cursor.toArray() returns a promise as it has to iterate all the query results at once before consturcting the results array. Sometimes this operation might be time consuming yielding delayed server response. So you may instead use the cursor.forEach() method to process the documents returned from the query one by one like a stream. Which means processing the first document and then iterating to the next one. Here is another example to show how it might be implemented.
function artpromise (artist) {
const MongoClient = require("mongodb").MongoClient;
return MongoClient.connect('mongodb://majac.co.kr:27017') // connect to mongo server
.then(function(mc){
var cursor = mc.db('artbot') // get mongoClient object and connect to artbot db
.collection('artistdb') // connect to the artistdb collection
.find({name: artist}); // get the cursor
return [mc, cursor]; // return mongoClient and cursor objects
});
}
let artist = "Italian";
artpromise(artist).then(function([mc,docs]){
docs.forEach(doc => console.log(doc), // process a document and then iterate to the next
() => mc.close()); // close db session when all documents are processed
})
.catch(e => console.log(e)); // catch errors
[nodemon] starting `node maeror_v2.js`
{ _id: 5abdbc18423795deaafeff13,
nationality: 'Dutch',
art_link: 'https://media.mutualart.com/Images/2012_04/15/13/132154856/ddf14e9d-85b1-4b5a-b621-00583e013879_570.Jpeg',
years: '1839 - 1902',
name: 'Frederick Hendrik Kaemmerer',
art_title: ' A Beach Stroll ' }
[nodemon] clean exit - waiting for changes before restart
This is my mongoDb connection
var mongoose = require('mongoose');
// Connection URL
var db = 'mongodb://localhost:27017/employeeDetails';
// Use connect method to connect to the Server
mongoose.connect(db, function (error) {
if (error) {
console.log(error);
}
});
var Schema = mongoose.Schema;
var Employee_Schema = new Schema({
EmployeeName: String,
Designation: String,
Project: String,
Skills:String
});
var Employee = mongoose.model('employees', Employee_Schema);
module.exports=Employee;
This is my api code (express.js)
var express=require('express');
var router=express.Router();
var Employee=require('../database/dataFile');
router.get('/',function(req,resp,next){
Employee.find({},function(err,docs){
resp.send(docs);
})
});
router.post('/create',function(req, resp, next){
var employee_collection =Employee.collection(Employee);
employee_collection.insert(req.body, function(err, doc) {
if(err) throw err;
console.log(doc);
res.json(doc);
});
});
module.exports=router;
This is my $http.post
create(employee: Employee) {
return this.http.post('http://localhost:4500/api/create', employee).map((response: Response) => response.json());
}
I always get
Failed to load resource: the server responded with a status of 500
(Internal Server Error)
FYI: $http.get works fine. It fetches data from MongoDb. The following hit the get method in api
getEmployeeList() {
return this.http.get('http://localhost:4500/api');
}
Please note I am taking example from here
This tutorial does not have Post functionality and I am trying to implement.
There Is A problem with the query, If you want to fetch the collection use:
mongoose.getCollection(<collection name>), But here you are calling the collection function on a model object, not the mongoose one.
Instead, I Would recommend using .create directly:
Employee.create(req.body, function(err,result){
if(err){throw Error(err)}
return res.json(result);
})
I'm using the mongoose ODM for a project. My schema looks like this:
const applicantSchema = new Schema({
regno: {
type: String,
unique: true,
required: true
},
email: {
type: String,
unique: true,
required: true
}
});
const Applicant = mongoose.model('Applicant', applicantSchema);
I created a wrapper function to add a new document which looks like this:
function addApplicant(newApplicant, callback){
mongoose.connect(url);
const db = mongoose.connection;
console.log(newApplicant);
console.log(typeof newApplicant);
const applicant = new Applicant(newApplicant);
applicant.save((err) => {
if(err) return callback(err);
let info = "successfully saved target";
return callback(null, info);
});
}
I call this function within my route that handles the concerned post request.
router.post('/applicant/response', (req, res) => {
//process sent response here and add to DB
//console.log(req.body);
let newApplicant = {
regno: req.body.regno,
email: req.body.email
}
//console.log(newApplicant);
applicant.addApplicant(newApplicant, (err, info) => {
if(err){ console.log(err); res.end(err);}
res.end('complete, resp: ' + info);
});
});
However, mongoose gives me a validation error (path 'regno' is required) even though I am supplying a value for regno. This happens with all the fields marked as required.
If I remove the 'required: true' option the document is saved to the db as expected.
Any help will be appreciated. :)
It turns out that in this case, something was wrong with the way postman was sending data in a POST request. When I tested this later in postman using JSON as the data format (and ensuring that the Content-Type header is set to application/json), the code worked as expected.
To those facing a similar issue, check the headers postman sends with the request, and ensure that they are what you'd expect them to be.
In your express entry file where you expose your endpoints and setup express you should have app.use(express.json()); written above the endpoint.
const express = require("express");
require("./src/db/mongoose");
const User = require("./src/models/user");
const app = express();
const port = process.env.PORT || 3000;
// THIS LINE IS MANDATORY
app.use(express.json());
app.post("/users", async(req, res) => {
const user = new User(req.body);
try {
await user.status(201).save();
res.send(user);
} catch (error) {
res.status(400).send(error);
}
});
app.listen(port, () => {
console.log(`Server is runnung in port ${port}`);
});
This question already has answers here:
How do I manage MongoDB connections in a Node.js web application?
(13 answers)
Closed 4 years ago.
I've read a few guides on how to use Mongo with Node, and they all seem to connect to databases differently. One particular way that worked well for me was:
MongoClient.connect("mongodb://localhost:27017/exampleDb", function(err, db) {
if(err) { return console.dir(err); }
db.createCollection('users', function(err, collection) {});
//Do all server/database operations in here
});
However, this seems inefficient/odd to me, I would have to reconnect to the database every time there is an app.get(), like for making a new user or retrieving information.
Another way that seems better suited to me is
var mongoose = require("mongoose")
var db = mongoose.connect("localhost:27107/users");
db.createCollection('users', function(err, collection) {});
I've seen several sites do something along these lines, but I personally can't get the above to work. I keep getting the error TypeError: db.createCollection is not a function server-side. So, my question is why the above code doesn't work, if the first code is a good alternative, and if there are any other ways to do this.
You can use a global variable to hold the connection (e.g. db), for example:
var db = null // global variable to hold the connection
MongoClient.connect('mongodb://localhost:27017/', function(err, client) {
if(err) { console.error(err) }
db = client.db('test') // once connected, assign the connection to the global variable
})
app.get('/', function(req, res) {
db.collection('test').find({}).toArray(function(err, docs) {
if(err) { console.error(err) }
res.send(JSON.stringify(docs))
})
})
Or, if you prefer, you can also use the Promise object that is returned by MongoClient if it is called without a callback argument:
var conn = MongoClient.connect('mongodb://localhost:27017/') // returns a Promise
app.get('/', function(req, res) {
conn.then(client=> client.db('test').collection('test').find({}).toArray(function(err, docs) {
if(err) { console.error(err) }
res.send(JSON.stringify(docs))
}))
})
Please note that I used the ES6 fat arrow function definition in the second example.
You are absolutely correct that you should not call MongoClient every time. Using a global variable or Promises allows the MongoDB node.js driver to create a connection pool, which achieves at least two good things:
Connections are reused in a pool, so there is no multiple expensive setup/teardown process for the lifetime of your application. You connect once, and let the driver take care of the rest for you.
You can control the amount of connection your application makes into the database, by limiting the size of the connection pool.
Edit 2018-08-24: The MongoClient.connect() method in node.js driver version 3.0 and newer returns a client object instead of a database object. The examples above were modified to keep it up to date with the latest node.js driver version.
I've written a tutorial on how to reuse mongodb connection in express. You can see here. Basically, it's a simple module, which you can use with expressjs like that:
var connection = require('./dbconnection');
// url and optional config.
app.use(connection(app, 'mongourl', {});
And here's the code for the connection:
module.exports = function(app, uri, opts) {
if (typeof uri !== 'string') {
throw new TypeError('Error: Unexpected mongodb connection url');
}
opts = opts || {};
var property = opts.property || 'db';
var connection;
return function expressMongoDb(req, res, next) {
if (!connection) {
connection = MongoClient.connect(uri, opts);
}
connection
.then(function (db) {
req[property] = db;
app.set('mongodb', db);
next();
})
.catch(function (err) {
connection = undefined;
next(err);
});
};
};
You could use it this way:
that's server.js file:
import path from 'path'
import express from 'express'
import bodyParser from 'body-parser'
import morgan from 'morgan'
import db from './server/database'
import routes from './server/routes'
import webpack from 'webpack'
import webpackDevMiddleware from 'webpack-dev-middleware'
import webpackHotMiddleware from 'webpack-hot-middleware'
import webpackConfig from './config/webpack'
const app = express()
const port = process.env.PORT || process.env.NODE_PORT
const compiler = webpack(webpackConfig)
db(λ => {
app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: webpackConfig.output.publicPath }))
app.use(webpackHotMiddleware(compiler))
app.use(morgan('dev'))
app.use(bodyParser.json({ limit: '20mb' }))
app.use(bodyParser.urlencoded({ limit: '20mb', extended: false }))
app.use('/static', express.static('static'));
//app.use('/api', jwt)
app.use('/api', routes())
app.set('json spaces', 2)
app.get('*', function(request, response) {
response.sendFile(path.resolve(__dirname, 'index.html'))
})
app.listen(port, (error) => {
if (error) {
console.error(error)
throw error
} else {
console.info(`==> 🌎 Listening on port ${port}. Open up http://localhost:${port}/ in your browser.`)
}
})
})
server/database.js
import mongoose from 'mongoose'
export default callback => {
const { MONGO_URL, MONGO_PORT, MONGO_DB } = process.env
mongoose.connect(`mongodb://${MONGO_URL}:${MONGO_PORT}/${MONGO_DB}`, error => {
if (error) {
console.error('Please make sure your MongoDB configuration is correct and that service is running')
throw error
}
})
callback()
}
Then you'll have to define your mongoose models, for instance:
import mongoose, { Schema } from 'mongoose'
const ideaSchema = new Schema({
title: {
type: String,
required: true
},
slug: {
type: String,
required: true,
unique: true
},
description: {
type: String,
required: true
}
})
export default mongoose.model('Idea', ideaSchema)
And just use controllers this way:
import HttpStatus from 'http-status-codes'
import mongoose from 'mongoose'
import sanitize from 'sanitize-html'
import slug from 'slug'
import Idea from '../models/idea'
const findAllIdeas = (req, res) => {
Idea.find()
.select('user title slug createdAt updatedAt')
.populate({
path: 'user',
select: 'firstName lastName'
})
.then(data => res.status(HttpStatus.OK).json(data))
.catch(error => res.status(HttpStatus.BAD_REQUEST).json(error))
}
export default { findAllIdeas, findIdeaBySlug, createIdea, addComment }
You will not have to connect to mongoDB for each get request.
So your route will look like that. Quite straightforward:
import { Router } from 'express'
import controller from '../controllers/idea'
const router = Router()
router.route('/')
.get(controller.findAllIdeas)
.post(controller.createIdea)
router.route('/:slug')
.get(controller.findIdeaBySlug)
router.route('/comment')
.post(controller.addComment)
export default router
My go-to code is as follows:
mongoose.connect(YOUR_URL ,function(err) {
if (err) {
console.log(err);
}else{
console.log("Connected to DB");
}
});
Also try connecting to just localhost:27107, that may be your problem.