使用 geonear 的 Mongoose 聚合 [英] Mongoose aggregation with geonear

查看:18
本文介绍了使用 geonear 的 Mongoose 聚合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 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.

但是,虽然目前 mongoose .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 ) );
      });

    });

  }
);

所以你在光标上使用了 skiplimit 操作,返回了一个光标,甚至将文档处理回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()

这篇关于使用 geonear 的 Mongoose 聚合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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