更改mongodb时更新客户端中的位置

时间:2016-01-06 14:57:35

标签: node.js mongodb express socket.io

我正在制作一个anroid应用程序并使用express for backend。 这是我的送货男孩架构

var DeliveryBoySchema = new Schema({

    name: String,
    college: {type:String},
    password: {type: String, required: true, select: false},
    lat:{type: String},
    long:{type:String}

});

当送货员改变它的位置时,它会在mongodb中更新。 因此,正在查看此送货员的用户即正在跟踪其位置的用户。我找到了两种方法:

1 。客户端每隔5秒调用一次api并获取送货员的当前位置。

2 。我发现了另一个有趣的方法,即使用套接字。

我对它的功能不太清楚。我在如何在数据库发生更改并且用户看到当前位置时更新客户端时遇到问题。

2 个答案:

答案 0 :(得分:4)

仅使用mongoosenodeJSsocket从OP请求的某些编码。实际实施不必完全相同,但以下内容应提供有关如何继续并填补缺失空白的一般概念。为方便起见,我将仅使用ES6功能。

nodeJS版本 4.2.2 ,socket.io 1.3.5 ,mongoose版本 4.1.2 ,快递 4.13.3

  1. 创建套接字 - 服务器端
  2. //the following is probably your app.js
    import express from 'express'
    ...
    var app = express();
    var server = http.createServer(app);
    ...
    
    var socketio = require('socket.io')(server, {
      path: '/socket.io-path, //modify this as per your needs
    });
    //now register created socket object
    require('./components/socket')(socketio);
    
    ...
    //start the server

    //the following is components/socket/index.js
    
    function onConnect(socket){
       //register listeners on mongo schema changes
       require('../../models/deliveryBoy.socket').register(socket);
    }
    
    module.exports = function(socketio){
      socketio.on('connection', function(socket) {
        socket.address = socket.request.connection.remoteAddress +
          ':' + socket.request.connection.remotePort; 
        //address, e.g. 127.0.0.1:52243
    
        socket.connectedAt = new Date();
        socket.log = function(...data) {
          console.log(`SocketIO ${socket.address}`, ...data);
        };
        // Call onDisconnect.
        socket.on('disconnect', function() {
          socket.log('Disconnected: ');
          //do something when user disconnects
        });
    
        // Call onConnect.
        onConnect(socket);
        socket.log('New connection: ');
      });
    };

    1. 在mongoose架构定义上附加一个挂钩
    2. //this is to be stored at ./models/deliveryBoy.model 
      
      'use strict';
      
      var mongoose = require('bluebird').promisifyAll(require('mongoose'));
      var Schema = mongoose.Schema;
      
      var DeliveryBoySchema = new Schema({
          name: String,
          college: {type:String},
          password: {type: String, required: true, select: false},
          lat:{type: String},
          long:{type:String}
      });
      
      //attach a hook to be triggered every time you modify the document
      //has to be inserted before the mongoose model is created !!!
      //with !!!ATTENTION!!! update method using $set
      //for example DeliveryBoy.update({_id:'blah'}, {$set: {long: 1, lat: 0}});
      DeliveryBoySchema.post('update', function(){
      	var update = this._update;
      	if (update.$set && (update.$set.lat || update.$set.long)){
      		try{
      			var updatedObjectId = this._conditions._id; //will serve as a room
                  var newLoc = {
                    lat: update.$set.lat,
                    long: update.$set.long
                  }
      			//now emit the event using nodejs event emitter
      
                  require('../../components/app.events').emit('updateLoc', {roomId: updatedObjectId, newLoc: newLoc}); 
      		}
      	}
      });
      
      module.exports = mongoose.model('DeliveryBoy', DeliveryBoySchema);

      1. DeliveryBoy的套接字侦听器
      2. //this is the component which implement socket specifically for delivery boy model
        //it is called (register method) from general components/socket module
        
        exports.register = function(socket){
          AppEvents.on('updateLoc', function(socket){
            return function(info){
              socket.to(info.roomId).emit('newLocation', info.newLoc);
            }
          });
        }

        1. 现在您只需要根据deliveryboy id从客户端连接到房间并使用来自客户端的消息并相应地更新您的视图
        2. 还有一件事,就是如何从REST API更新数据库

          app.put('/update/:gameId', function(req, res){
              DeliveryBoy.update({_id: req.params.gameId}, {$set: req.body}, function(err){
                res.send(200); //of course this needs to be handled properly, but i am too tired after typing all these
                //you owe me couple beers dude
          });
          });

          P.S 代码有点混乱,但您应该能够做出相应的改进。如果有任何问题,请告诉我。但基本概念应该是明确的

答案 1 :(得分:0)

解决方案1并不好,只是因为您的服务器会膨胀并且无法立即响应。忘了这个:)简单地说,首次应用程序加载时,应该只从服务器查询一次该位置。

你可能会认为送货员是一个游戏。假设为了简单起见,只有1名玩家​​和几名观众。玩家是触发更新的人。观众只能跟踪变化。基本上玩家和观众都在同一个房间,这意味着他们只有在发生变化时才应该更新。

  • 从玩家的角度来看,这很简单,他是唯一可以影响位置的人,你可以同时要求服务器更新送货员的位置并改变你在视图上的位置。这里没问题。每当您的玩家更改送货员的位置时,您绝对需要持续存储更新。
  • 从观众的角度来看。每次在数据存储中发生位置更新时,您需要通知连接到房间的每个人有关位置变化的信息。有很多方法可以解决这个问题。但很可能你必须以某种方式使用套接字(除了一些XMPP客户端解决方案,它们要复杂得多)。

简单地说,关键是选择正确的沟通渠道。我个人会用redis来存储位置,创建订阅频道并通过频道向套接字发布更新。更新位置后,您将持续更新redis中的位置,将更改发布到通道(通过队列),通过订阅使用更改并通过套接字将更新传递给所有侦听客户端。 为何选择redis? 1.适用于分布式系统(可扩展)2。PUB / SUB是一个队列,无需为了同步而获得癌症3. PUB / SUB是持久的4.实际上比纯数据库解决方案更快(与MongoDB相比)