Mongoose/MongoDb 收到错误 geoNear 不是函数
Posted
技术标签:
【中文标题】Mongoose/MongoDb 收到错误 geoNear 不是函数【英文标题】:Mongoose/MongoDb getting error geoNear is not a function 【发布时间】:2018-06-14 08:25:48 【问题描述】:这是我的控制器文件 locations.js
var mongoose = require('mongoose');
var Loc = mongoose.model('location');
module.exports.locationsListByDistance = function(req, res)
var lng = parseFloat(req.query.lng);
var lat = parseFloat(req.query.lat);
var point =
type: "Point",
coordinates: [lng, lat]
;
var geoOptions =
spherical: true,
maxDistance: 1000
;
Loc.geoNear(point, geoOptions, function (err, results, stats)
console.log(results);
);
;
我的模型文件locations.js
var mongoose = require('mongoose');
var reviewSchema = new mongoose.Schema(
author: String,
rating:
type: Number,
required: true,
min: 0,
max: 5
,
reviewText: String,
createdOn:
type: Date,
"default": Date.now
);
var openingTimeSchema = new mongoose.Schema(
days:
type: String,
required: true
,
opening: String,
closing: String,
closed:
type: Boolean,
required: true
);
var locationSchema = new mongoose.Schema(
name:
type: String,
required: true
,
address: String,
rating:
type: Number,
"default": 0,
min: 0,
max: 5
,
facilities: [String],
// Always store coordinates longitude, latitude order.
coords:
type: [Number],
index: '2dsphere'
,
openingTimes: [openingTimeSchema],
reviews: [reviewSchema]
);
mongoose.model('location', locationSchema, 'locations');
每当我运行 http://localhost:3000/api/locations?lng=-0.9690884&lat=51.455041 时,我都会收到错误 geoNear is not a function
TypeError: Loc.geoNear 不是函数 在 module.exports.locationsListByDistance (/home/shackers/Projects/mean/loc8r/app_api/controllers/locations.js:51:7) 在 Layer.handle [as handle_request] (/home/shackers/Projects/mean/loc8r/node_modules/express/lib/router/layer.js:95:5) 在下一个(/home/shackers/Projects/mean/loc8r/node_modules/express/lib/router/route.js:137:13) 在 Route.dispatch (/home/shackers/Projects/mean/loc8r/node_modules/express/lib/router/route.js:112:3) 在 Layer.handle [as handle_request] (/home/shackers/Projects/mean/loc8r/node_modules/express/lib/router/layer.js:95:5) 在/home/shackers/Projects/mean/loc8r/node_modules/express/lib/router/index.js:281:22 在 Function.process_params (/home/shackers/Projects/mean/loc8r/node_modules/express/lib/router/index.js:335:12) 在下一个(/home/shackers/Projects/mean/loc8r/node_modules/express/lib/router/index.js:275:10) 在 Function.handle (/home/shackers/Projects/mean/loc8r/node_modules/express/lib/router/index.js:174:3) 在路由器(/home/shackers/Projects/mean/loc8r/node_modules/express/lib/router/index.js:47:12) 在 Layer.handle [as handle_request] (/home/shackers/Projects/mean/loc8r/node_modules/express/lib/router/layer.js:95:5) 在 trim_prefix (/home/shackers/Projects/mean/loc8r/node_modules/express/lib/router/index.js:317:13) 在/home/shackers/Projects/mean/loc8r/node_modules/express/lib/router/index.js:284:7 在 Function.process_params (/home/shackers/Projects/mean/loc8r/node_modules/express/lib/router/index.js:335:12) 在下一个(/home/shackers/Projects/mean/loc8r/node_modules/express/lib/router/index.js:275:10) 在 /home/shackers/Projects/mean/loc8r/node_modules/express/lib/router/index.js:635:15
这是我正在使用的依赖版本:
节点:8.9.3 npm:5.5.1 express:4.15.5 mongoose:5.0.0 mongoDb:3.6.1【问题讨论】:
我遇到了完全相同的问题 - 你找到解决方案了吗?? 【参考方案1】:router.get('/', () =>
Loc.aggregate([
$geoNear:
near: 'Point',
distanceField: "dist.calculated",
maxDistance: 100000,
spherical: true
]).then(function(err, results, next)
res.send();
).catch(next);
);
参考:-https://docs.mongodb.com/manual/reference/command/geoNear/
【讨论】:
我这里有同样的问题,但是我不明白聚合的使用,可以解释一下吗? @krekto 我不是 Mongo 专家,但这里是 Mongo 聚合管道的相关 documentation。我相信聚合管道只是在数据库中“查找”文档的另一种方式,并且恰好也具有 geoNear 功能。如果我错了,欢迎其他人纠正我。 @krekto-db.students.aggregate([ $grades: rank: 'A', group: _id: "$student_id", total: $sum: "$score" , sort: total: -1 ]) 代码美化/缩进这个例子。上面的操作选择排名等于“A”的学生文档,按照 student_id 字段对匹配的文档进行分组,并计算每个文档的总和student_id 字段从金额字段的总和,并按总字段的降序对结果进行排序。我希望这有助于理解聚合。 @deechris27 明白了,tx【参考方案2】:发生此错误是因为 .geoNear
曾经受支持,但从使用 Node MongoDB v3 驱动程序的 Mongoose 5 开始不再受支持。
Migrating to Mongoose 5 文档中记录了该问题,该文档又链接到 MongoDB 3 drive release notes,该文档提供了有关推荐替换的声明:
geoNear 命令的功能在语言的其他地方、未分片集合的 $near/$nearSphere 查询运算符以及所有集合的 $geoNear 聚合阶段都有重复。
实际上,官方文档认可在其他答案中记录的$geoNear
的使用。
【讨论】:
【参考方案3】:我遇到了完全相同的问题,我已经放弃了以前使用的方法(看起来你也有)。以下是一种不会引发错误的替代方法,并且应该会为您提供与使用 Loc.geoNear 后相同的结果:
Loc.aggregate(
[
'$geoNear':
'near': point,
'spherical': true,
'distanceField': 'dist',
'maxDistance': 1000
],
function(err, results)
// do what you want with the results here
)
【讨论】:
我这里有同样的问题,但是我不明白聚合的使用,可以解释一下吗?【参考方案4】:显然,我在同一本书(Getting Mean, Manning)中遇到了大致相同的问题。这似乎对我有用:
var mongoose = require('mongoose');
var Loc = mongoose.model('Location');
var sendJSONresponse = function(res, status, content)
res.status(status);
res.json(content);
;
var theEarth = (function()
console.log('theEarth');
var earthRadius = 6371; // km, miles is 3959
var getDistanceFromRads = function(rads)
return parseFloat(rads * earthRadius);
;
var getRadsFromDistance = function(distance)
return parseFloat(distance / earthRadius);
;
return
getDistanceFromRads: getDistanceFromRads,
getRadsFromDistance: getRadsFromDistance
;
)();
/* GET list of locations */
module.exports.locationsListByDistance = function(req, res)
console.log('locationsListByDistance:');
var lng = parseFloat(req.query.lng);
var lat = parseFloat(req.query.lat);
var maxDistance = parseFloat(req.query.maxDistance);
var point =
type: "Point",
coordinates: [lng, lat]
;
console.log('point: ' + point)
var geoOptions =
spherical: true,
maxDistance: theEarth.getRadsFromDistance(maxDistance),
num: 10
;
console.log('geoOptions: ' + geoOptions);
if ((!lng && lng!==0) || (!lat && lat!==0) || ! maxDistance)
console.log('locationsListByDistance missing params');
sendJSONresponse(res, 404,
"message": "lng, lat and maxDistance query parameters are all required"
);
return;
else
console.log('locationsListByDistance running...');
Loc.aggregate(
[
'$geoNear':
'near': point,
'spherical': true,
'distanceField': 'dist.calculated',
'maxDistance': maxDistance
],
function(err, results)
if (err)
sendJSONresponse(res, 404, err);
else
locations = buildLocationList(req, res, results);
sendJSONresponse(res, 200, locations);
)
;
;
var buildLocationList = function(req, res, results)
console.log('buildLocationList:');
var locations = [];
results.forEach(function(doc)
locations.push(
distance: doc.dist.calculated,
name: doc.name,
address: doc.address,
rating: doc.rating,
facilities: doc.facilities,
_id: doc._id
);
);
return locations;
;
返回一个类似这样的结果列表:
[
"distance": 0,
"name": "Rathaus",
"address": "Markt",
"rating": 0,
"facilities": [
"museum"
],
"_id": "5a9366517775811a449e503e"
,
"distance": 61.77676881925853,
"name": "Haus Löwenstein",
"address": "",
"rating": 0,
"facilities": [
"museum"
],
"_id": "5a9366517775811a449e5045"
,
"distance": 63.03445976427102,
"name": "Goldener Schwan",
"address": "Markt 37",
"rating": 0,
"facilities": [
"restaurant"
],
"_id": "5a9366517775811a449e5052"
,
"distance": 66.60375653163021,
"name": "Klein Printenbäckerei",
"address": "Krämerstraße 12",
"rating": 0,
"facilities": [
"supermarket"
],
"_id": "5a9366517775811a449e504d"
,
"distance": 74.91278395082011,
"name": "Couven-Museum",
"address": "Hühnermarkt 17",
"rating": 0,
"facilities": [
"museum"
],
"_id": "5a9366517775811a449e5042"
,
"distance": 132.2939512054143,
"name": "Cathedral Treasury",
"address": "Johannes-Paul-II.-Straße",
"rating": 0,
"facilities": [
"museum"
],
"_id": "5a9366517775811a449e503d"
,
"distance": 152.11867357742042,
"name": "Aachen Cathedral",
"address": "Domhof 1",
"rating": 0,
"facilities": [
"museum"
],
"_id": "5a9366517775811a449e503c"
,
"distance": 155.92015153163268,
"name": "International Newspaper Museum",
"address": "Pontstraße 13",
"rating": 0,
"facilities": [
"museum"
],
"_id": "5a9366517775811a449e5040"
,
"distance": 175.0857109968383,
"name": "Nobis Printen",
"address": "Münsterplatz 3",
"rating": 0,
"facilities": [
"supermarket"
],
"_id": "5a9366517775811a449e504c"
,
"distance": 179.32348875834543,
"name": "Grashaus",
"address": "Fischmarkt",
"rating": 0,
"facilities": [
"museum"
],
"_id": "5a9366517775811a449e5044"
,
"distance": 189.8675948747873,
"name": "Maranello",
"address": "Pontstraße 23",
"rating": 0,
"facilities": [
"restaurant"
],
"_id": "5a9366517775811a449e5057"
,
"distance": 198.2239741555585,
"name": "Carlos I",
"address": "Rennbahn 1",
"rating": 0,
"facilities": [
"restaurant"
],
"_id": "5a9366517775811a449e5055"
]
不确定它有多准确 - 加载了一个地址列表,并且不能 100% 确定随机混乱中的内容是什么……但它会返回一个列表,我会在某个时候以某种方式测试正确性。
【讨论】:
您的代码中不再需要对象geoOptions
,因为您已经在聚合中使用了 $geoNear
属性,而没有传递在控制台日志正下方声明的对象。
另外一件事,你还需要改变数据模型&集合:数据模型=>coords: type: type: String, default: "Point", coordinates: type: [Number]
数据集=>"coords" : "type": "Point", "coordinates": [-0.9690884, 51.455041]
【参考方案5】:
我找到了解决方案。只需降级猫鼬并安装版本 4.9.1。最新版本的 mongoose 不支持 Loc.geoNear
npm remove mongoose
npm install mongoose@4.9.1
【讨论】:
【参考方案6】:比 Grider 课程中的前两个答案更直接的 IMO 是:
index(req, res, next)
const lng, lat = req.query;
Driver.find(
'geometry.coordinates':
$nearSphere:
$geometry:
type: 'Point',
coordinates:[parseFloat(lng), parseFloat(lat)]
,
$maxDistance: 200000,
,
)
.then(drivers => res.send(drivers))
.catch(next);
这与他给出的原始定义的精神相一致,并使用了与旧 geoNear 做同样事情的新函数,除了它们现在已经分离出球形和非球形版本。你需要:
beforeEach((done) =>
const drivers = mongoose.connection.collections;
drivers.drop()
.then(() => drivers.createIndex( 'geometry.coordinates': '2dsphere' ))
.then(() => done())
.catch(() => done());
;
在前面提到的测试助手中。
【讨论】:
最好和最简单的出路。我正在使用$geoNear
aggregate 但是当我完成这个解决方案时,我用这个最简单的解决方案完全替换了聚合【参考方案7】:
我想你正在寻找这个,如果那里有错误,请纠正我。
module.exports.locationsListBydistance = function (req, res)
var lng = parseFloat(req.query.lng);
var lat = parseFloat(req.query.lat);
Loc.aggregate(
[
$geoNear:
'near': 'type':'Point', 'coordinates':[lng, lat],
'spherical': true,
'maxdistance': theEarth.getRadsFromDistance(20),
'num':10,
'distanceField': 'dist'
], function(err, results)
var locations = [];
console.log(results);
results.forEach(function (doc)
locations.push(
distance: theEarth.getDistanceFromRads(doc.dist),
name: doc.name,
address: doc.address,
facilities: doc.facilities,
rating: doc.rating,
_id: doc._id
);
);
sendJsonResponse(res, 200, locations);
);
;
【讨论】:
【参考方案8】:router.get('/',function(req,res,next)
Loc.aggregate([
$geoNear:
near: type:'Point', coordinates:[parseFloat(req.query.lng), parseFloat(req.query.lat)],
distanceField: "dist.calculated",
maxDistance: 1000,
spherical: true
]).then(function(Locs)
res.send(Locs)
)
)
【讨论】:
你能解释一下你的代码以及它是如何回答这个问题的吗?【参考方案9】:用户给出的答案:phao5814 非常正确,我试过了,必须说它对我来说效果很好
【讨论】:
欢迎来到 ***。在这里,“我也是”的回答是通过对好的答案投票而不是添加新答案来处理的。【参考方案10】: index(req, res, next)
const lng, lat = req.query;
Driver.aggregate([
'$geoNear':
"near": 'type': 'Point',
'coordinates': [parseFloat(lng), parseFloat(lat)] ,
"spherical": true,
"distanceField": 'dist',
"maxDistance": 200000
])
.then(drivers => res.send(drivers))
.catch(next);
【讨论】:
如果您正在学习当前托管在 Udemy 上的 Stephen Grider 的课程“MongoDB 的完整开发人员指南”,上面的代码可以完美运行。确保将 beforeEach 属性更改为 ".then(() => drivers.createIndexes(..." 以避免警告。以上是关于Mongoose/MongoDb 收到错误 geoNear 不是函数的主要内容,如果未能解决你的问题,请参考以下文章
mongoose mongodb nodejs的bodyparser错误
mongoose mongodb nodejs的bodyparser错误