Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/41.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js NodeJS和Mongo line谁';s在线_Node.js_Mongodb - Fatal编程技术网

Node.js NodeJS和Mongo line谁';s在线

Node.js NodeJS和Mongo line谁';s在线,node.js,mongodb,Node.js,Mongodb,TL;博士 记录在线用户并报告计数(基于mongo查找) 我们已经为学校和学生提供了一个saas应用程序,作为其中的一部分,我一直想要一个在线股票报价器 学校的老师会看到计数器,学生和家长会触发它 我有一个从web应用到NodeJS应用的socket.io连接。 在流量很大的地方,Node/Mongo服务器无法处理它,我认为与其花费更多的资源,不如对代码进行优化——因为我不知道我在做什么:D 对于每个学生页面加载: 使用以下对象创建socket.io连接: { 'name': 'student

TL;博士

记录在线用户并报告计数(基于mongo查找)


我们已经为学校和学生提供了一个saas应用程序,作为其中的一部分,我一直想要一个在线股票报价器

学校的老师会看到计数器,学生和家长会触发它

我有一个从web应用到NodeJS应用的socket.io连接。 在流量很大的地方,Node/Mongo服务器无法处理它,我认为与其花费更多的资源,不如对代码进行优化——因为我不知道我在做什么:D

对于每个学生页面加载: 使用以下对象创建socket.io连接:

{
'name': 'student or caregiver name',
'studentID': 123456,
'schoolID': 123,
'role': 'student', // ( or 'mother' or 'father' )
'page': window.location
}
在我的节点脚本中:

io.on('connection', function(client) {
    // if it's a student connection.. 
    if(client.handshake.query.studentID) {
        let student = client.handshake.query; // that student object
            student.online = new Date();
            student.offline = null;
        db.collection('students').updateOne({ 
           "reference": student.schoolID + student.studentID + student.role }, { $set: student 
        }, { upsert: true });


    }

    // IF STAFF::: just show count!
    if(client.handshake.query.staffID) {
      db.collection('students').find({ 'offline': null, 'schoolID':client.handshake.query.schoolID }).count(function(err, students_connected) {
          
          emit('online_users' students_connected);
       });
    }



    client.on('disconnect', function() {
        // then if the students leaves the page..
        if(client.handshake.query.studentID) {
            db.collection('students').updateMany({ "reference": student.reference }, { $set: { "offline": new Date().getTime() } })
            .catch(function(er) {});
         }

         // IF STAFF::: just show updated count!
         if(client.handshake.query.staffID) {
           db.collection('students').find({ 'offline': null, 'schoolID':client.handshake.query.schoolID }).count(function(err, students_connected) {
          
                emit('online_users' students_connected);
            });
         }
     });
});


您会添加什么Mongo索引,您会将在线学生以不同的方式(和不同的集合)存储到像这样的“页面跟踪”类型的交易中吗? (这会记录页面和持续时间,因此我稍后会有另一个调用来拉取该页面-但这并不是频繁使用或导致问题的原因

如果单独,则插入,然后删除

EMIT()对于staff用户,如何仅向与学生具有相同schoolID的staff发送


谢谢!

如果不进一步讨论这个问题,这将不是一个完整的答案,但我想我会发布一些一般性的建议

首先,我们应该弄清楚性能瓶颈在哪里。这是一个特定的查询吗?是否有太多的同时连接到MongoDB?是否每个查询都有太多的往返时间(如果两台服务器不在同一个数据中心内)?这里有很多要缩小的地方。集合中有多少文档?MongoDB服务器可以访问多少RAM?这将让我们知道此时是否应该存在缩放问题。我可以在获得有关该问题的更多信息后编辑我的答案

基于我们目前已知的,不进行任何模型更改,您可以考虑索引<代码>引用<代码>字段,以便使UpSert调用更快(如果这是瓶颈)。

db.collection('students').createIndex({
  "reference": 1
},
{ background: true });
如果查询是瓶颈,您可以创建如下索引:

db.collection('students').createIndex({
  "schoolID": 1
},
{ background: true });

我不相信(在不了解更多数据的情况下)在索引中包含
脱机
会有帮助,因为优化“notnull”可能会很棘手。根据数据的不同,这可能会导致以不同的方式存储数据(如您所建议的).

您已经简要介绍了这个问题,但没有对问题发生的原因进行诊断。基于一些假设,我将尝试回答您的问题

首先,您提到,您希望得到关于哪些索引可以帮助您解决问题的建议,根据您提到的内容,这是一个写操作繁重的系统,原则上索引只会减慢写操作,因为在每次写操作中,处理索引的Btree也必须更新。尽管读操作变得更好,特别是在ca中她收集了大量的数据

因此,如果你的收藏中有100万份文档,那么索引可以帮你大忙。它可以帮助你只浏览所需的数据,甚至不用扫描所有数据,这要归功于Btree

索引应该专门根据您所做的读取调用创建

例如

{"student_id" : "studentID", "student_fname" : "Fname"}
如果此处的读取调用基于
student\u id
,则在该基础上创建和索引,如果涉及多个值(相等-排序或任何内容),则在这些字段上创建复合索引,首先优先考虑相等字段,然后优先考虑范围和排序字段

现在是问题的第二部分,在这种情况下什么更好

这是一件主观的事情,我相信每个人对此都会有不同的方法。我的解决方案基于一些假设

假设

该系统需要满足一个特定的功能,即学生的在线状态在某个时间间隔内更新,数据可供家长、教师等阅读

您正在使用的套接字,如果它们一直保持连续连接,那么与服务器的并发连接就太多了,如果需要或不需要,我不知道。但是,正如您已经知道的那样,并发连接对服务器来说很重,除非需要,否则100%尝试混合方法

如果你断开一段时间,或者保持与服务器的连接只需很短的时间,那么请考虑这一点。这基本上意味着,你与服务器断开连接,连接发送数据并重复。 或者,只要采用心跳系统,你的前端应用程序将在设定的时间间隔后调用API并ping服务器,基于此,你可以处理学生是否在线,稍微延迟一点,是的,但很容易扩展

请使用redis或任何其他内存中数据存储进行频繁写入,特别是在不需要长时间保存数据的情况下

例如,假设我们为用户的每个类/部分使用redis列表,并且仅在从前端接收到他们的最后一次心跳时更新时间戳(历元)

在一个有60名学生的班级里,根据学生id或类似的东西对学生进行排序

为该类创建一个列表

对于升迁学生列表中的第一个学生id,更新如下历元

LSET mylist 0 "1266126162661" //Epoch Time Stamp 
0是您的第一个学生,59是我们的第60个学生,请在每次心跳时更新它。通过API或您拥有的相同套接字系统。取决于您的用例

当需要读调用时

LRANGE classname/listname 0 59
现在您有了所有用户的时代,可以通过数据库或其他列表维护学生列表,您可以在其中简单地将索引与特定学生匹配

LSET studentList 0 "student_id" //Student id of the student or any other data, I am trying to explain the logic
在前端,当您有历元时,根据您的用例考虑最新的历元,例如,假设我希望学生在线,如果hearbeat在5分钟后收到

当前时间戳-时间戳(如果小于5分钟