mongooseで地理情報を扱う(aggregate().near())


前提

概要

いろいろあるけど、Aggregateの$geoNearを使うと距離も取得できていい感じ
Mongooseではnearなので注意。なぜgeoNearではないのかは不明

サンプルソース

mongoose接続情報、省略

Mongoose Model Place

../models/place
const mongoose = require('mongoose')
const Schema = mongoose.Schema;
const geoSchema = new Schema({
  type        : { type : String   , default : 'Point'},
  coordinates : { type : [Number] , default : [0,0] }
});

const placeSchema = new Schema({
  place_id   : { type : String, required : [false, 'Place id is required'], default:'new' },
  place_name : { type : String, default:'new place' },
  location   : { type : geoSchema , index: '2dsphere', default: geoSchema },
  lastupdate : { type : Date, default: Date.now},
});

const Place = mongoose.model('Place', placeSchema);
module.exports = {Place}

実行用ファイル
require('../config/config.js')
const { mongoose } = require("../db/mongoose");
const { Place } = require("../models/place");

//サンプルデータ定義
// http://gihyo.jp/dev/serial/01/mongodb/0009
const places=[
  { place_id : '1', place_name : '五反田',  location:{ type:'Point', coordinates:[ 139.723822, 35.625974 ]}},
  { place_id : '2', place_name : '恵比寿',  location:{ type:'Point', coordinates:[ 139.710070, 35.646685 ]}},
  { place_id : '3', place_name : '新宿',    location:{ type:'Point', coordinates:[ 139.700464, 35.689729 ]}},
  { place_id : '4', place_name : '新大久保',location:{ type:'Point', coordinates:[ 139.700261, 35.700875 ]}},
  { place_id : '5', place_name : '池袋',    location:{ type:'Point', coordinates:[ 139.711086, 35.730256 ]}},
  { place_id : '6', place_name : '上野',    location:{ type:'Point', coordinates:[ 139.777043, 35.713790 ]}},
  { place_id : '7', place_name : '品川',    location:{ type:'Point', coordinates:[ 139.738999, 35.628760 ]}}
]
// テーブル初期化
async function populatePlaces()  {
  await Place.deleteMany({});
  await Place.insertMany(places);
}

//近い順にPlaceデータ取得 GeoNear(aggregate) 
//https://mongoosejs.com/docs/api.html#aggregate_Aggregate-near
async function geonear(limit){
  const results = await Place.aggregate()
  .near({
    near: { type : "Point", coordinates: [139.701238, 35.658871] },  //渋谷駅
    spherical: true, 
    distanceField: "distance", //メートル
  })
  .limit(limit)
  console.log(results)
}

//メイン関数
async function main(){
  await populatePlaces() //コレクション初期化
  await geonear(3)  //近い方から3つ表示
}
main()

実行結果

恵比寿、新宿、五反田が帰ってくる。
距離はdistanceにメートルで保存されている。

以上。