猫鼬聚集与土拨鼠 [英] Mongoose aggregation with geonear

查看:168
本文介绍了猫鼬聚集与土拨鼠的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Mongoose geoNear命令实现分页. geoNear似乎不支持跳过,并且我知道聚合可以工作(使用具有性能成本的分页).如何将其转换为聚合查询以跳过许多文档?

I'm trying to implement paging with Mongoose geoNear command. It seem skip is not supported with geoNear, and I understand aggregation would work (with paging with a performance cost). How can I convert this to aggregation query to skip a number of documents?

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
        });
    }
};

推荐答案

您可以为此使用聚合框架,并且由于操作基本相同,因此没有实际的代价.

You can use the aggregation framework for this and there is no real penalty as the operations are essentially the same.

但是,虽然猫鼬.find()方法目前在 $nearSphere 运算符,您可以始终获取原始节点驱动程序连接对象并进行查询.

But while the mongoose .find() method presently has a problem with the $nearSphere operator which is equivalent, you can always grab the raw node driver connection object and do your query.

如果您准备进行一些处理,甚至不需要扔掉人口"之类的东西.

You do not even need to throw away things like "population" if you are prepared to implement a little handling.

这是我的测试数据:

{ 
    "_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")
}

以及处理此问题的基本代码:

And the basic code to handle this:

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()之类的功能.

So there you got usage of both the skip and limit operations on the cursor, had a cursor returned and even processed the documents back into "Mongoose Documents" so you can call functions like .populate() on them.

我希望 $nearSphere 出现当前问题>不过要尽快修复.

I would expect the current issue with $nearSphere to be fixed relatively soon though.

或改为使用聚合:

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().两种情况都返回匹配填充"字段的结果:

Where you can do the same things such as use .populate(). Both cases return results like this with the "populated" field matched:

{
    "_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()

Of course if you do not need the spherical geometry calculation then the $near operator works perfectly fine with the Mongoose implementation of .find()

这篇关于猫鼬聚集与土拨鼠的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆