【问题标题】:Using MongoDB for real-time chat database使用MongoDB做实时聊天数据库
【发布时间】:2020-05-17 22:41:07
【问题描述】:

我正在从事一个个人项目,以提高我在 Nodejs、Express、Socket.io 和 MongoDB 方面的技能和经验。我似乎在制定数据库应该如何为这种应用程序工作时遇到了障碍。我一直在考虑它,并且可以从任何可能需要一些时间的人那里获得一些帮助。我的应用程序允许用户输入用户名并选择房间标题。在此之后,他们被加载到房间中,其他人可以加入该房间并实时聊天。我想保留数据,在断开连接时为每个房间保存它,并在连接时重新填充它。 每个房间都有一个与之关联的名称和消息本身。每条消息都有一个发件人名称、时间戳和文本/内容。 但是当涉及到实际构建模型以及如何组织集合时,我会感到困惑。任何人都可以帮助我或让我走上此类申请的正确道路吗?

server.js(后端)

require('dotenv').config();
const path = require('path');
const http = require('http');
const express = require('express');
const socketio = require('socket.io');
const mongoose = require('mongoose');
const formatMessage = require('./utils/messages');
const {
    userJoin,
    getCurrentUser,
    userLeave,
    getRoomUsers
} = require('./utils/users');

const app = express();
const server = http.createServer(app);
const io = socketio(server);

// Set static folder
app.use(express.static(path.join(__dirname, 'public')));

const botName = 'ChatCord Bot';
const messages = [];


//Database connection
const uri = process.env.ATLAS_URI;

mongoose.connect(uri, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
    useCreateIndex: true
});

const connection = mongoose.connection;
connection.once('open', () => {
    console.log("MongoDB database connection established successfully");
})







// Run when client connects
io.on('connection', socket => {
    socket.on('joinRoom', ({
        username,
        room
    }) => {
        const user = userJoin(socket.id, username, room);

        socket.join(user.room);

        // Welcome current user
        socket.emit('message', formatMessage(botName, 'Welcome to ChatCord!'));


        //Load messages for room from database
        socket.broadcast.to(user.room).emit(
            'message', formatMessage()
        )


        // Broadcast when a user connects
        socket.broadcast
            .to(user.room)
            .emit(
                'message',
                formatMessage(botName, `${user.username} has joined the chat`)
            );

        // Send users and room info
        io.to(user.room).emit('roomUsers', {
            room: user.room,
            users: getRoomUsers(user.room)
        });

    });

    // Listen for chatMessage
    socket.on('chatMessage', msg => {
        const user = getCurrentUser(socket.id);

        io.to(user.room).emit('message', formatMessage(user.username, msg));
    });

    // Runs when client disconnects
    socket.on('disconnect', () => {
        const user = userLeave(socket.id);

        if (user) {
            io.to(user.room).emit(
                'message',
                formatMessage(botName, `${user.username} has left the chat`)
            );

            // Send users and room info
            io.to(user.room).emit('roomUsers', {
                room: user.room,
                users: getRoomUsers(user.room)
            });
        }

            //Save messages for room to database

    });
});

const PORT = process.env.PORT || 3000;

server.listen(PORT, () => console.log(`Server running on port ${PORT}`));

main.js(前端)

const chatForm = document.getElementById('chat-form');
const chatMessages = document.querySelector('.chat-messages');
const roomName = document.getElementById('room-name');
const userList = document.getElementById('users');


//Get username and room from URL

const {username, room } = Qs.parse(location.search, {
    ignoreQueryPrefix: true

});

console.log(username, room);



const socket = io();

//Join chatroom
socket.emit('joinRoom', {username, room});

//Get room and users
socket.on('roomUsers', ({ room, users }) => {
    outputRoomName(room);
    outputUsers(users);
})


socket.on('message', message => {
    outputMessage(message);

    //Scroll down on new message
    chatMessages.scrollTop = chatMessages.scrollHeight;

});

//Message submit
chatForm.addEventListener('submit', (e) => {
    e.preventDefault();

    //Get message text
    const msg = e.target.elements.msg.value;

    //Emit message to server
    socket.emit('chatMessage',msg);

    //Clear input
    e.target.elements.msg.value = '';
    e.target.elements.msg.focus();


});

//Output message to DOM

function outputMessage(message) {
    const div = document.createElement('div');
    div.classList.add('message');
    div.innerHTML = `<p class="meta">${message.username} <span>${message.time}</span></p>
    <p class="text">
        ${message.text}
    </p>`;
    document.querySelector('.chat-messages').appendChild(div);
}

//Add room name to DOM
function outputRoomName(room) {
    roomName.innerText = room;

}


//Add users to DOM
function outputUsers(users) {
    userList.innerHTML = `${users.map(user => `<li>${user.username}</li>`).join('')}`;

}

room.model.js

const mongoose = require('mongoose');

const Schema = mongoose.Schema;

const roomSchema = new Schema({
    id: mongoose.ObjectId,
    messages: [
        {
            id: mongoose.ObjectId,
            authorUsername: String,
            time: Date,
            content: String  
        }
    ]
});

const Room = mongoose.model("Room", roomSchema);

module.exports = Room;

users.js

const users = [];

//Join user to chat

function userJoin(id, username, room) {
    const user = {id, username, room};

    users.push(user);

    return user;
}

//Get current user
function getCurrentUser(id) {
    return users.find(user => user.id === id);
}

//User leaves chat

function userLeave(id) {
    const index = users.findIndex(user => user.id === id);

    if(index !== -1) {
        return users.splice(index, 1)[0];
    }
}

//Get room users

function getRoomUsers(room) {
    return users.filter(user => user.room === room);
}


module.exports = {
    userJoin,
    getCurrentUser,
    userLeave,
    getRoomUsers
}

【问题讨论】:

    标签: node.js mongodb mongoose


    【解决方案1】:

    一种简单的方法是仅使用一个模式构建数据库,即Room 模式。
    当用户在房间中发送消息时,推送到同一房间的消息数组。
    然后,在 socket.io(节点)中,您发出一个套接字(带有房间 id)并发送消息,并在客户端设置用户接收该房间的所有套接字。

    房间架构:

    { ID, 消息:[ { ID, 作者用户名, 内容 } ] }

    【讨论】:

    • 非常感谢!这很有帮助!这些 id 元素中的任何一个都需要特定类型吗?
    • @KortneyStinson 只使用 mongoose 的 ObjectId 类型 mongoosejs.com/docs/schematypes.html#objectids
    • 谢谢!我更新了我的问题以显示我在代码中实际在做什么。有时间可以看一下吗?我需要一些帮助来执行你提到的一些事情。我应该推送到我正在侦听聊天消息的 socket.on() 中的数组吗?
    • 在客户端我们有 html&&vanila 时一切正常 || jQuery,如果我们以 React 为例,用 mongo 维护实时更新真的很困难(几乎不可能)。我们应该使用 firebase 或其他响应式 db-s。
    猜你喜欢
    • 2011-02-25
    • 2014-12-21
    • 2023-04-06
    • 2021-11-09
    • 2023-04-04
    • 2015-03-06
    • 1970-01-01
    • 2013-10-10
    • 2020-06-13
    相关资源
    最近更新 更多