Reputation: 2541
I'm building a web site in React, Redux, Express and Socket io using the starter of ErikRas: https://github.com/erikras/react-redux-universal-hot-example
It looks crazy to me: so many tutorials for react and redux. no want say how to implement MongoDb. I hope the answer will be useful for other people too. In fact, all the starters we can find on the web avoid to talk and give exemples about the data storage. ...Maybe because it pushes too far the complexity. I don't know. So... I'm trying to add MongoDb. The tutorials show different ways, but always with pure node.js and express, and often with an extremely easy setting. But the api of the starter isn't easy at all, and I got lost! I don't know if I have to connect it all in api.js, or server.js or... I'm extremely confuse!!!
I set up the MongoDb and it works fine. I already charged some data in it by the terminal. Then, in the api.js I added some lines (commented in the following code):
import express from 'express';
import session from 'express-session';
import bodyParser from 'body-parser';
import config from '../src/config';
import * as actions from './actions/index';
import {mapUrl} from 'utils/url.js';
import PrettyError from 'pretty-error';
import http from 'http';
import SocketIo from 'socket.io';
// --------------- New Code
var mongo = require('mongodb');
var monk = require('monk');
var db = monk('localhost:27017/nodetest1');
// --------------------------------------
const pretty = new PrettyError();
const app = express();
const server = new http.Server(app);
const io = new SocketIo(server);
io.path('/ws');
app.use(session({
secret: 'react and redux rule!!!!',
resave: false,
saveUninitialized: false,
cookie: { maxAge: 60000 }
}));
app.use(bodyParser.json());
app.use((req, res) => {
const splittedUrlPath = req.url.split('?')[0].split('/').slice(1);
const {action, params} = mapUrl(actions, splittedUrlPath);
if (action) {
action(req, params)
.then((result) => {
if (result instanceof Function) {
result(res);
} else {
res.json(result);
}
}, (reason) => {
if (reason && reason.redirect) {
res.redirect(reason.redirect);
} else {
console.error('API ERROR:', pretty.render(reason));
res.status(reason.status || 500).json(reason);
}
});
} else {
res.status(404).end('NOT FOUND');
}
});
// -------------------> New code -> 'II part'
app.use(function(req,res,next){
req.db = db;
next();
});
// --------------------------------
const bufferSize = 100;
const messageBuffer = new Array(bufferSize);
let messageIndex = 0;
if (config.apiPort) {
const runnable = app.listen(config.apiPort, (err) => {
if (err) {
console.error(err);
}
console.info('----\n==> 🌎 API is running on port %s', config.apiPort);
console.info('==> 💻 Send requests to http://%s:%s', config.apiHost, config.apiPort);
});
io.on('connection', (socket) => {
socket.emit('news', {msg: `'Hello World!' from server`});
socket.on('history', () => {
for (let index = 0; index < bufferSize; index++) {
const msgNo = (messageIndex + index) % bufferSize;
const msg = messageBuffer[msgNo];
if (msg) {
socket.emit('msg', msg);
}
}
});
socket.on('msg', (data) => {
data.id = messageIndex;
messageBuffer[messageIndex % bufferSize] = data;
messageIndex++;
io.emit('msg', data);
});
});
io.listen(runnable);
} else {
console.error('==> ERROR: No PORT environment variable has been specified');
}
...but that gives right away an error in the terminal saying:
proxy error { Error: connect ECONNREFUSED 127.0.0.1:3030
at Object.exports._errnoException (until.js953:11)
at exports._exceptionWithHostPort (until.js:976:20)
at TCPConnectWrap.afterConnect [as oncomplete ] (net.js:1080:14)
code: 'ECONNREFUSED'
errno: 'ECONNREFUSED'
syscall: 'connect'
address: '127.0.0.1'
port: 3030 }
Where and how do I have to implement MongoDb? Why I got the error even when the second part of the code I added is not there? Any link for a usefull doc?
Thank you in advance!
Upvotes: 2
Views: 718
Reputation: 2541
So, here I come with a solution. I'll try to leave an answer as the one I would like to find.
For the moment, I just achieved to write in the Mongo Database. But a lot of work reste to do. And I'm not sure the way I use it is the best for the performance. So feel free to improve it and developpe a complete answer.
So, here how I did to use MongoDb with express and socket.io. I'm building my site from the boilerplate of Erik Ras
https://github.com/erikras/react-redux-universal-hot-example
Install MongoDb on your computer. It will install Mongo in C:\ I did it twice, the second time it was installed in Porgrams.
Create a new folder called "data" inside the folder called api.
Then navigate with the terminal inside the MongoDb folder and find bin. From there, digit the path to the data folder:
mongod --dbpath c:\nameofthefolderproject\api\data
Mongo initialize the data store (it takes a moment), starts and waits for connection.
Navigate with the terminal in the root of your project and installe mongoose:
npm install mongoose
Then open the file nameofthefolderproject\api\api.js There import mongoose:
import mongoose from 'mongoose';
and add right after the imports:
var mongoURI = "mongodb://localhost/nameofyourproject";
var db = mongoose.connect(mongoURI, function(err){
if(err){
console.log(err);
}else{
console.log('Finally connected!!!');
}
});
You should recive the message in the terminal.
Create a folder in the api folder called: nameofthefolderproject\api\models
Inside create the file nameofthefolderproject\api\models\members.js
Create a mongoose schema. Look at the doc to understand it if you don't know it.
var mongoose = require('mongoose');
var membersSchema = mongoose.Schema({
pseudo:{
type: String,
required: true
},
email:{
type: String,
required: true
},
date:{
type: Date,
default: Date.now
}
});
var Members = module.exports = mongoose.model('members', membersSchema);
Create the file: nameofthefolderproject\api\models\index.js and write the following. Here you will collect all the models exporting everything ready to use.
export members from './members';
When the api calls the action, pass the models to the function.
app.use(bodyParser.json());
app.use((req, res) => {
const splittedUrlPath = req.url.split('?')[0].split('/').slice(1);
const {action, params} = mapUrl(actions, splittedUrlPath);
// it calls the right action passing also the mongoose schemas (models)
if (action) {
action(req, params, models) etc etc...
Now go in the action called by the server. In my case: nameofthefolderproject\api\actions\addMember You can now use the model to register. In my case:
export default function addMember(req, err, models) {
// this is the function called by the api. I passed all the models of mongoose.
return new Promise((resolve, reject) => {
// charge the data received from the form in a variable
var data = req.body;
// extract the mongoose model I interested about.
var Members = models.members;
// initialise the mongoose schema and connect the data received to the schema
var newMember = new Members({pseudo:data.pseudo, email:data.email});
// In this way I can register the data in mongodb data store
newMember.save(function(err, data){
// verify if there is an error, and confirm eventually the success
if(err){
throw err;
reject();
}
resolve();
});
});
}
If I'll have the time in next days I'll develop the rest and I post it.
Enjoy.
Max
Upvotes: 2
Reputation: 2541
thank you for the quick answer. In fact, the server.js uses the port 3030. But MongoDb uses port 27017. That's way I don't understand why the two can't work together. as I add:
// --------------- New Code
var mongo = require('mongodb');
var monk = require('monk');
var db = monk('localhost:27017/nodetest1');
// --------------------------------------
...it gets crazy :-)
I use "express": "^4.13.3" and node is v 6.2.0
Upvotes: 0