MongoDB聚合:$geoNear-举例

时间:2024-02-18 19:59:30

places插入下面的数据:

db.places.insertMany( [
   {
      name: "Central Park",
      location: { type: "Point", coordinates: [ -73.97, 40.77 ] },
      category: "Parks"
   },
   {
      name: "Sara D. Roosevelt Park",
      location: { type: "Point", coordinates: [ -73.9928, 40.7193 ] },
      category: "Parks"
   },
   {
      name: "Polo Grounds",
      location: { type: "Point", coordinates: [ -73.9375, 40.8303 ] },
      category: "Stadiums"
   }
] )

下面的操作为location字段创建一个2dsphere索引:

db.places.createIndex( { location: "2dsphere" } )

最大距离

上面的places集合有一个2dsphere索引,下面的聚合使用$geoNear查找位置距离中心点[ -73.99279 , 40.719296 ]最多2米距离且category等于Parks的文档。

db.places.aggregate([
   {
     $geoNear: {
        near: { type: "Point", coordinates: [ -73.99279 , 40.719296 ] },
        distanceField: "dist.calculated",
        maxDistance: 2,
        query: { category: "Parks" },
        includeLocs: "dist.location",
        spherical: true
     }
   }
])

聚合返回下面的结果:

{
   "_id" : 8,
   "name" : "Sara D. Roosevelt Park",
   "category" : "Parks",
   "location" : {
      "type" : "Point",
      "coordinates" : [ -73.9928, 40.7193 ]
   },
   "dist" : {
      "calculated" : 0.9539931676365992,
      "location" : {
         "type" : "Point",
         "coordinates" : [ -73.9928, 40.7193 ]
      }
   }
}

匹配的文档包含两个新字段:

  • dist.calculated字段,包含了计算后的距离
  • dist.location字段,包含了用于计算的位置

最小距离

下面的示例使用minDistance选项来指定文档与中心点的最小距离。下面的聚合查找所有位置距离中心点[ -73.99279 , 40.719296 ]至少2米距离且category等于Parks的文档。

db.places.aggregate([
   {
     $geoNear: {
        near: { type: "Point", coordinates: [ -73.99279 , 40.719296 ] },
        distanceField: "dist.calculated",
        minDistance: 2,
        query: { category: "Parks" },
        includeLocs: "dist.location",
        spherical: true
     }
   }
])

使用let选项

在下面的例子中:

  • let选项用于将数组[-73.99279,40.719296]的值设置给变量$pt
  • pt被指定为near参数的let选项。
db.places.aggregate(
[
   {
      "$geoNear":
      {
         "near":"$$pt",
         "distanceField":"distance",
         "maxDistance":2,
         "query":{"category":"Parks"},
         "includeLocs":"dist.location",
         "spherical":true
      }
   }
],
{
   "let":{ "pt": [ -73.99279, 40.719296 ] }
}
)

聚合返回符合下面条件的所有文档:

  • 距离let变量指定的点至少2米距离
  • category等于Parks
{
   _id: ObjectId("61715cf9b0c1d171bb498fd7"),
   name: 'Sara D. Roosevelt Park',
   location: { type: 'Point', coordinates: [ -73.9928, 40.7193 ] },
   category: 'Parks',
   distance: 1.4957325341976439e-7,
   dist: { location: { type: 'Point', coordinates: [ -73.9928, 40.7193 ] } }
},
{
   _id: ObjectId("61715cf9b0c1d171bb498fd6"),
   name: 'Central Park',
   location: { type: 'Point', coordinates: [ -73.97, 40.77 ] },
   category: 'Parks',
   distance: 0.0009348548688841822,
   dist: { location: { type: 'Point', coordinates: [ -73.97, 40.77 ] } }
}

使用绑定let选项

let选项可以绑定一个变量用于$geoNear查询。

在下面的例子中,$lookup

  • 使用let定义$pt
  • pipeline使用$geoNear阶段。
  • $geoNear阶段用pt定义near
db.places.aggregate( [
   {
      $lookup: {
         from: "places",
         let: { pt: "$location" },
         pipeline: [
            {
               $geoNear: {
                  near: "$$pt",
                  distanceField: "distance"
               }
            }
         ],
         as: "joinedField"
      }
   },
   {
      $match: { name: "Sara D. Roosevelt Park" }
   }
] );

聚合返回的结果中:

  • Sara D. Roosevelt Park文档作为主文档。
  • 将地点集合中的每个文档作为子文档,使用$pt变量计算距离。
{
   _id: ObjectId("61715cf9b0c1d171bb498fd7"),
      name: 'Sara D. Roosevelt Park',
      location: { type: 'Point', coordinates: [ -73.9928, 40.7193 ] },
      category: 'Parks',
      joinedField: [
         {
         _id: ObjectId("61715cf9b0c1d171bb498fd7"),
         name: 'Sara D. Roosevelt Park',
         location: { type: 'Point', coordinates: [ -73.9928, 40.7193 ] },
         category: 'Parks',
         distance: 0
         },
         {
         _id: ObjectId("61715cf9b0c1d171bb498fd6"),
         name: 'Central Park',
         location: { type: 'Point', coordinates: [ -73.97, 40.77 ] },
         category: 'Parks',
         distance: 5962.448255234964
         },
         {
         _id: ObjectId("61715cfab0c1d171bb498fd8"),
         name: 'Polo Grounds',
         location: { type: 'Point', coordinates: [ -73.9375, 40.8303 ] },
         category: 'Stadiums',
         distance: 13206.535424939102
         }
      ]
}

指定地理空间索引

假定有一个places集合,该集合的location字段上有一个2dsphere索引,legacy字段上有一个2d索引。

places集合中的文档类似这个:

{
   "_id" : 3,
   "name" : "Polo Grounds",
   "location": {
      "type" : "Point",
      "coordinates" : [ -73.9375, 40.8303 ]
   },
   "legacy" : [ -73.9375, 40.8303 ],
   "category" : "Stadiums"
}

下面的例子使用key选项,为$geoNear聚合操作指定使用location字段的值而不是使用legacy字段的值。聚合管道同事使用$limit返回最多5个文档。

db.places.aggregate([
   {
     $geoNear: {
        near: { type: "Point", coordinates: [ -73.98142 , 40.71782 ] },
        key: "location",
        distanceField: "dist.calculated",
        query: { "category": "Parks" }
     }
   },
   { $limit: 5 }
])

聚合返回下面的结果:

{
   "_id" : 8,
   "name" : "Sara D. Roosevelt Park",
   "location" : {
      "type" : "Point",
      "coordinates" : [
         -73.9928,
         40.7193
      ]
   },
   "category" : "Parks",
   "dist" : {
      "calculated" : 974.175764916902
   }
}
{
   "_id" : 1,
   "name" : "Central Park",
   "location" : {
      "type" : "Point",
      "coordinates" : [
         -73.97,
         40.77
      ]
   },
   "legacy" : [
      -73.97,
      40.77
   ],
   "category" : "Parks",
   "dist" : {
      "calculated" : 5887.92792958097
   }
}