Friend Based System in Node.js - javascript

So I currently have a real-time chat application up and running with node and socket.io. What I would like to do from here is let users create an account and search for other users based on their usernames. Then, they can add them as a friend via request to start chatting.
I have looked around the web to try and answer this question, but cannot find any solid starting point. I am brand new to node.js, express, and socket.io, and would love some help with this issue.
If you could point me in the right direction as to how I can create a friend based system using node, that would be amazing. Thanks!

I too think this is a broad question but I will try to give you the glimpse of a technological aspect of what you are trying to do.
First of all, you should have a user management system, including login, signup, forget password etc. You can use passport.js for this. Now, you have a complete user management system, you can start further.
If you are willing to friend request/accept feature that eventually control the chat system, You might wanna create a database structure like below.
const mongoose = require('mongoose'),
Schema = mongoose.Schema;
// Schema defines how chat messages will be stored in MongoDB
const FriendsSchema = new Schema({
participants: [{ type: Schema.Types.ObjectId, ref: 'user' }],
requestTo: {type: Schema.Types.ObjectId, ref: 'user'},
accepted: {tyoe: Boolen, default:false}
});
module.exports = mongoose.model('Friends', FriendsSchema);
You can check this database to create a friendship request, check friendship between two users etc. And another thing you shoud do in database is to create model for chats. To save messages, Like below:
const mongoose = require('mongoose'),
Schema = mongoose.Schema;
const MessageSchema = new Schema({
friendshipId: {
type: Schema.Types.ObjectId,
required: true,
ref: 'Friends'
},
body: {
type: String,
required: true
},
author: {
type: Schema.Types.ObjectId,
ref: 'user'
},
seen: {
type: Boolean,
default: false
},
delivered: {
type: Boolean,
default: false
}
},
{
timestamps: true // Saves createdAt and updatedAt as dates. createdAt will be our timestamp.
});
module.exports = mongoose.model('Message', MessageSchema);
Now, for the real-time chat system you should integrate both socket.io and databases. You can do it like below code.
var http = require('http')
var redis = require('redis')
var client = redis.createClient()
module.exports = (app) => {
const server = http.createServer(app)
const io = require('socket.io').listen(server)
io.sockets.on('connection', (socket) => {
socket.on('sendChat', (user, msg, messageId) => {
client.get(user, function(err, socketId){
io.to(socketId).emit('updateChat', socket.username, msg, messageId)
})
})
socket.on('delivered', (user, messageId) => {
client.get(user, function(err, socketId){
io.to(socketId).emit('delivered', messageId)
})
})
socket.on('seen', (user, messageId) => {
client.get(user, function(err, socketId){
io.to(socketId).emit('seen', messageId)
})
})
socket.on('adduser', (username) => {
client.set(username, socket.id, function(err){
socket.username = username
io.sockets.emit('updateOnlineUser', username)
})
})
socket.on('disconnect', function(){
client.del(socket.username)
io.sockets.emit('updateOfflineUser', socket.username)
})
})
}
What happens above? It basically create a connection to client and when the client sends a addUser event to server it stores user in radis store. And when messages are transferred through socket, by sending sendChat event, it sends events to another chat user. You will also need to save this chat to database as well.
And when users do not want to send message to inactive users, which are not connected through socket. You must implement endpoints for messaging tasks. For more info please follow through this open source project.

Related

How to craft Post requests for MEAN Stack?

I am currently programming a reminders app based on this project in an effort to learn JS and MEAN Stack. As part of my project, I am trying to add a date which each reminder is to be completed by. However, when using Postman to POST in a date, I am receiving an error message unless I cut the date field and only use JSON to put the reminder's title in. If I use Javascript for my POST, it greys out the title field in my POST's body and when I attempt to use JSON, the time field's entry is not recognized. The pertinent code is below. Any help is appreciated.
const express = require('express');
const app = express();
const mongoose = require('./db/mongoose');
const bodyParser = require('body-parser');
const {List, Reminder} = require('./db/models')
app.post('/lists/:listId/reminder', (req, res) => {//add a reminder to the specified list
let newReminder = new Reminder({
title: req.body.title,
_listId: req.params.listId,
time: req.body.time
});
newReminder.save().then((newReminderDoc) => {
res.send(newReminderDoc);
})
})
const mongoose = require('mongoose');
const ReminderSchema = new mongoose.Schema({
title:{
type: String,
required: true,
minlength: 1,
trim: true
},
_listId:{
type: mongoose.Types.ObjectId,
required: true
},
time:{
type: Date,
required: true
}
});
const Reminder = mongoose.model('Reminder', ReminderSchema);
module.exports = { Reminder }
JS Query I am trying to used:
{
title: "Test",
created: new Date("2016-12-12")
}

Mongoose not saving data according to a function (discord.js)

Today, I decided to make a Discord RPG bot which of course requires profile stats such as coins and the actual users. Therefore, I searched up a tutorial on how I can do this with MongoDB but I am running into one issue. When a guild member joins and the bot is running, the data does not save with no error at all and I am unsure of why this is happening. I have tried troubleshooting the connection status by adding a line console.log(mongoose.connection.readyState) after the bot attempts to connect to the database. This returns 1 which means the connection is fine. I cannot find any other reason why this is caused so I decided to ask a question after hours of thinking.
(index.js): Connecting to the database
const mongoose = require("mongoose");
mongoose.connect(process.env.MONGO_SERVER, {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => [
console.log("Connected to MongoDB Database successfully!"),
console.log(mongoose.connection.readyState)
]).catch((err) => {
console.error(err);
});
(profileSchema.js): Creating a profile schema
const mongoose = require("mongoose");
const profileSchema = new mongoose.Schema({
id: { type: String, require: true, unique: true },
serverid: { type: String, require: true },
coins: { type: Number, default: 0 },
bank: { type: Number }
});
const model = mongoose.model("ProfileModels", profileSchema);
module.exports = model;
(guildMemberAdd.js): Creating and uploading the data into the database
const profileModel = require('../models/profileSchema');
module.exports = async(client, discord, member) => {
let profile = await profileModel.create({
id: member.id,
serverid: member.guild.id,
coins: 0,
bank: 0
})
profile.save();
}
The reason is to do with the way you connect to mongo
BY default mongo closes the connection after connecting to a database. To do this, when connecting to mongo pass in the keepAlive option, so it would look something like:
mongoose.connect(process.env.MONGO_SERVER, {
useNewUrlParser: true,
useUnifiedTopology: true,
keepAlive: true
})
This will then mean an active connection to your database will be kept open
You are exporting 'model' from profileSchema.js and requiring 'profileModel ' from guildMemberAdd.js?
so import model from profileSchema and not profileModel
Fix: Make sure the guildMemberAdd event is being called by adding console.log statements.
If not, check if guildMemberAdd's code is different to other event codes.

Multi-tenant with mongoose and Node.js. One or multiple connection?

We are building an Saas application where we need, for technical reasons (backup, security), adopt a multi-tenants architecture (aka one DB per customer). We are using Node.js (with Typescript) and MongoDB (with mongoose driver).
For a first test, we are doing as below. Please note that it is a simple draft easily reproductible.
We start a new connection in index.ts, the "entry-point":
try {
//Define Mongo connection options
const mongoOptions = {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true,
useFindAndModify: false,
autoIndex: true,
poolSize: 10,
bufferMaxEntries: 0,
connectTimeoutMS: 10000,
socketTimeoutMS: 30000,
};
// Creating mongo connection
const connection = await mongoose.connect(
`mongodb://${process.env.MONGO_HOSTNAME}:${process.env.MONGO_PORT}`,
mongoOptions
);
// connectToMongoDB;
console.log('Successfuly connected to mongo database !');
} catch (err) {
console.log(err);
}
Then in a separate file, we have some logic for selecting the appropriate Database and return the Model :
import mongoose from 'mongoose';
export class ClientDbProvider {
static async getTenantDb(
tenantId: string,
modelName: string,
schema: mongoose.Schema
) {
const dbName = `spearateDB_${tenantId}`;
const db = mongoose.connection.useDb(dbName, { useCache: true });
db.model(modelName, schema);
return db;
}
static async getModelForDb(databaseName: string,
model: mongoose.Model<mongoose.Document>, schema: mongoose.Schema
) {
const connection = await ClientDbProvider.getTenantDb(
databaseName,
model.modelName,
schema
);
return connection.model(model.modelName);
}
}
Then, in any route, we include clientID for using the appropriate DB.
router.post('/api/data/:clientID', async (req: Request, res: Response) => {
const { name, value } = req.body;
const data = Data.build({
name: name,
value: value,
});
try {
const dataModel = await ClientDbProvider.getModelForDb(
req.params.clientID,
Data,
DataSchema
);
const doc = await dataModel.create(data);
} catch (err) {
console.log(err);
}
res.send({});
});
Basically we call ClientDbProvider.getModelForDb for getting a Model. The getModelForDb switches to a different database using the same connection pool and return a model.
Note on the app:
the database will be continuously fills by data as it will store telemetry data from several sensors (some can generate data every second, some every 10 minutes...)
The api will be mostly for reading data (send it as JSON).
Some queries could be long as it will depends on own many data the client ask (even if we will put some defaults limits).
We will never have a huge amount of customers (DB). We plan to have, for the next two years, 20 to 40 customers (we will upgrade to another architecture if needed such as Sharded cluster). In any cases, the number of customer will never be like 1 000 000 or so...
All DB are on the same server/mongo instance (for now)
Questions:
Does this 'draft' code could cause some trouble or performance issue ?
Would that make sense to create a connection per DB (customer) with mongoose.createConnection function and then cache the connection as describe here (in a global variable for example) ?
As all of our DB are on the same server, does increasing the pool of the connections isn't sufficient ?

"MissingSchemaError" when seeding database using mongoose-seeder

I am attempting to seed a database using mongoose-seeder, and I keep getting a MissingSchemaError. I am sure that I am setting up the schema properly, so I am lost as to why this is happening.
The file where I set up the schema looks like this:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserSchema = new Schema({
fullName: {
type: String,
required: true,
trim: true
},
emailAddress: {
type: String,
unique: true,
required: true,
match: /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)| .
(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-
Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
},
password: {
type: String,
required: true
}
});
const User = mongoose.model('User', UserSchema);
module.exports.User = User;
and in my main file:
'use strict';
// load modules
const morgan = require('morgan');
const mongoose = require('mongoose');
const seeder = require('mongoose-seeder');
const data = require('./data/data.json');
const express = require('express');
const app = express();
//set up database connection
mongoose.connect("mongodb://localhost:27017/courseapi");
const db = mongoose.connection;
//handle err connecting to db
db.on("error", (err) => console.error("Error connecting to database: ",
err));
//success
db.once("open", () => {
console.log("Connected to database");
seeder.seed(data, {dropDatabase: false}).then(function(dbData){
console.log("Database seeded!");
}).catch(function(err){
console.error("Error seeding database", err);
})
});
any help would be much appreciated!
The mongoose-seeder package is not maintained. Hence suggesting an alternative to import data. You can populate MongoDB in the CLI (command line interface) using mongoimport.It will load a JSON file into a specified MongoDB Instance & Collection. All you need is a mongod instance to be running before execution.
Please go through the walkthrough.
thank you for your help! The project required using a module to seed the data, so I ended up using mongoose-seed instead. (Required some reformatting of the json, but thankfully the file was relatively small)
it's better to use the actively maintained Seedgoose. It's the ultimate mongoose seeder with smart reference support.

Insert MongoDB document with React.js

I was wondering if there's a way to insert documents into a MongoDB collection directly from a React component.
My current personal project (for training purpose) is a little chat web application. So for example, when my user wants to post a new message in a room, the input component should look something like this:
var NewMessageInput = React.createClass({
postMessage: function(value) {
db.collection.insert({
content: value
});
},
render: function() {
return (
<div>
<input onSubmit={() => this.postMessage(value)}>Type your message here</input>
</div>
);
}
});
I know how to get an app running with Express, React, and MongoDB but I'm only able to insert document with the mongo shell and querying them at the route loading. Plus, I would like to use only react-router for my routes and that's why I have this question.
I'm guessing you'll need the database on the server, so you may need an API to post the data since the database itself isn't on the client.
I use Superagent for sending the data and Mongoose to create a schema and mongo database.
messageModel.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
// create a schema
const messageSchema = new Schema({
// You may need to add other fields like owner
addedOn: String,
message: String,
});
const Message = mongoose.model('Message', messageSchema);
module.exports = Message;
server.js
import Message from './models/messageModel';
mongoose.connect('mongodb://user:pass#localhost:port/database');
app.post('/api/messages', (req, res) => {
const doc = new Message({ message: req.body.message })
doc.save();
});
client.js
import React, { Component } from 'react';
import request from 'superagent';
class componentName extends Component {
constructor(props) {
super(props);
this.state = {
message: '',
};
this.handleMessageInput = this.handleMessageInput.bind(this);
}
handleMessageInput(e) {
this.setState({ message: e.target.value });
}
handleSubmitMessage() {
console.log('starting to submit profile');
if (this.state.isFormFilledProfile) {
console.log('Profile Form appears filled');
const data = {
message: this.state.message,
};
request
.post('/api/messages')
.send(data)
.set('Accept', 'application/json')
.end((err, res) => {
if (err || !res.ok) {
console.log('Oh no! err');
} else {
console.log('Success');
}
});
}
}
render() {
return (
<div>
<div>
<form onSubmit={this.handleSubmitMessage}>
<input
onChange={this.handleMessageInput}
value={this.state.message}
/>
<button type='Submit' value='Submit'>Submit</button>
</form>
</div>
</div>
);
}
}
export default componentName;
You may need to also go through the react forms guide here.
All the best!!!
Ok so because React is a front end framework you will not have access to things on your backend such as methods like db.collection.insert(). You will in tern has a separation of front end code and back end code. They will talk to each other through HTTP requests (GET, POST, PUT, DELETE).
Side note just to clarify. You will still need express for routing as well as react-router. They do different types of "routing". Express will handle routing of mainly your API, all the data calls that your front end will make to it. React-router handles page changes on your front end, right within the bowser. This keeps your page from reloading each time the user moves around.
So lets get into a little code.
On your back end you will need an express endpoint for your app to talk to. In this example I will show use with the package mongoose as it is a tool that is commonly used with a node.js backend.
https://www.npmjs.com/package/mongoose
var mongoose = require('mongoose');
var Message = require('../models/message');
app.post('/message', (req, res) => {
var newMessage = new Message(req.body);
newMessage.save((err, doc) => {
if (err) {
res.send(err);
} else {
res.send(doc);
}
});
});
This code will handle a post request at the url "/message". It will proceed to create a new message from the data in the request (req) body. Then save that to the database. After the save is successful it will send back the document that was just saved.
In mongoose we create a schema for each of our data models like such:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var MessageSchema = new Schema({
content: {
type: String,
},
createdAt: {
type: Date,
default: Date.now
}
});
var Message = mongoose.model('Message', MessageSchema);
module.exports = Message;
Now on the front end / React side of things we need to send our message data to the backend to save. We can use a package like axios to make clean promise based HTTP requests from the browser.
https://www.npmjs.com/package/axios
var NewMessageInput = React.createClass({
postMessage: function(value) {
axios.post('/message', {
content: value
})
.then(function (message) {
console.log(message);
})
},
render: function() {
return (
<div>
<input onSubmit={() => this.postMessage(value)}>Type your message here</input>
</div>
);
}
});
And that should do it!
For a backend example check out this repo I have setup. It's very basic but will be a good example of a backend with mongoose for reference.
https://github.com/Alexg2195/simple-dev-example
Also here is a bit of some side content I created for teaching React that may be a good reference.
https://github.com/Alexg2195/UT-ReactJS

Categories