与geonear的Mongoose聚合

时间:2014-06-19 01:48:32

标签: node.js mongodb mongoose geospatial aggregation-framework

我尝试使用Mongoose geoNear命令实现分页。 geoNear不支持跳过,我理解聚合会起作用(带有性能成本的分页)。如何将此转换为聚合查询以跳过多个文档?

exports.near = function(req, res) {
    if(req.query.lat && req.query.lng) {
        var point = {
            type: "Point", coordinates : [Number(req.query.lng), Number(req.query.lat)]
        };
        var queryParams = {
            spherical: true,
            skip: 0,
            limit: 10,
            distanceMultiplier: 6371 // radians to kilometers. (The radius of the Earth is approximately 3,959 miles or 6,371 kilometers.)
        };
        if(req.query.q) {
            var matcher = new RegExp(req.query.q, "i");
            queryParams.query = {
                $or: [
                    {'name': matcher },
                    {'address.full': matcher}
                ]
            };
        }
        if(req.query.limit) {
            queryParams.limit = parseInt(req.query.limit, 10);
        }
        if(req.query.offset) {
            queryParams.skip = parseInt(req.query.offset, 10);
        }
        Venue.geoNear(point, queryParams, function(error, results, stats) {
            // TODO
        });
    }
};

2 个答案:

答案 0 :(得分:6)

您可以使用聚合框架,因为操作基本相同,所以没有真正的惩罚。

但是,虽然mongoose .find()方法目前与$nearSphere运算符存在问题,但它始终可以获取原始节点驱动程序连接对象并执行查询。

如果你准备实施一点处理,你甚至不需要抛弃像“人口”这样的东西。

这是我的测试数据:

{ 
    "_id" : "P1",
    "amenity" : "restaurant", 
    "shape" : { 
        "type" : "Point", 
        "coordinates" : [ 2, 2 ] 
    }
}
{ 
    "_id" : "P3",
    "amenity" : "police",
    "shape" : { 
        "type" : "Point", 
        "coordinates" : [ 4, 2 ]
    }
}
{ 
    "_id" : "P4",
    "amenity" : "police",
    "shape" : {
        "type" : "Point",
        "coordinates" : [ 4, 4 ]
    }
}
{ 
    "_id" : "P2",
    "amenity" : "restaurant",
    "shape" : { 
        "type" : "Point",
        "coordinates" : [ 2, 4 ]
    }, 
    "info" : ObjectId("539b90543249ff8d18e863fb")
}

处理这个问题的基本代码:

var mongoose = require('mongoose'),
    async = require('async'),
    Schema = mongoose.Schema;


mongoose.connect('mongodb://localhost');

var infoSchema = new Schema({
  "description": String
});

var shapeSchema = new Schema({
  "_id": String,
  "amenity": String,
  "shape": {
    "type": { "type": String },
    "coordinates": []
  },
  "info": { "type": Schema.Types.ObjectId, "ref": "Info" }
});

var Shape = mongoose.model( "Shape", shapeSchema );
var Info = mongoose.model( "Info", infoSchema );


Shape.collection.find(
  {
    "shape": {
      "$nearSphere": {
        "$geometry": {
          "type": "Point",
          "coordinates": [ 2, 4 ]
        }
      }
    }
  },
  {
    "skip": 0, "limit": 2
  },
  function(err,cursor) {

    cursor.toArray(function(err,shapes) {

      Shape.populate( shapes, { path: "info" }, function(err,docs) {
        if (err) throw err;

        console.log( JSON.stringify( docs, undefined, 4 ) );
      });

    });

  }
);

因此你在光标上使用了 skip limit 操作,返回了光标,甚至将文档处理回“Mongoose Documents”,所以你可以在其上调用.populate()等函数。

我希望尽快修复$nearSphere的当前问题。

或者改为使用聚合:

Shape.aggregate(
  [
    { "$geoNear": {
        "near": {
          "type": "Point",
          "coordinates": [ 2, 4 ]
        },
        "spherical": true,
        "distanceField": "dis"
    }},
    { "$skip": 0 },
    { "$limit": 2 }

  ],
  function(err,shapes) {
    if (err) throw err;
    //console.log( shapes );

    shapes = shapes.map(function(x) {
      delete x.dis;
      return new Shape( x );
    });

    Shape.populate( shapes, { path: "info" }, function(err,docs) {
      if (err) throw err;

      console.log( JSON.stringify( docs, undefined, 4 ) );
    });

  }
);

您可以执行相同的操作,例如使用.populate()。这两种情况都返回这样的结果,其中“填充”字段匹配:

{
    "_id": "P2",
    "amenity": "restaurant",
    "info": {
        "_id": "539b90543249ff8d18e863fb",
        "description": "Jamies Restaurant",
        "__v": 0
    },
    "shape": {
        "type": "Point",
        "coordinates": [
            2,
            4
        ]
    }
},
{
    "info": null,
    "_id": "P4",
    "amenity": "police",
    "shape": {
        "type": "Point",
        "coordinates": [
            4,
            4
        ]
    }
}

当然,如果您不需要球面几何计算,那么$near运算符与.find()

的Mongoose实现完美匹配

答案 1 :(得分:0)

location.aggregate({"$geoNear": { "near": { "type": "Point", "coordinates": [parseFloat(req.params.lon), parseFloat(req.params.lat)] }, "maxDistance":500, 'distanceField' : 'distance', spherical: true
      }}, 
    function(err, places) {
   if(!err){
           console.log(places);
            res.send('({"records":' + JSON.stringify(places) + '});');
        }
        else{
            console.log(err);
            res.send("error coming")
        }
    });`

Above Query working fine in mongo shell but not working in mongoose