关于Nodejs mongoose aggregate的问题。请教各位大神

关于Nodejs mongoose aggregate的问题。请教各位大神

本地mongodb版本为2.6.4,线上mongodb版本为2.2.2。mongoose都为最新版本。

本地测试aggregate的$geoNear操作管道可以通过,但是线上没有通过,提示错误如下

{ [MongoError: Pipeline::run(): unrecognized pipeline op "$geoNear]
  name: 'MongoError',
  errmsg: 'Pipeline::run(): unrecognized pipeline op "$geoNear',
  ok: 0 }

是否mongodb版本的问题,如果是,能否轻易的升级版本呢,会有其他问题发生吗?请教,谢谢!


4 回复

针对您提到的问题,确实可能是由于不同版本的 MongoDB 支持的功能不同导致的。$geoNear 操作是在 MongoDB 3.2 版本中引入的,而您的线上环境使用的是 2.2.2 版本,这显然不支持 $geoNear

解决方案

  1. 升级 MongoDB 版本

    • 如果可能的话,升级线上 MongoDB 到 3.2 或更高版本。这是一个直接的解决方案,但需要评估升级过程中可能遇到的风险,如兼容性问题、数据迁移等。
  2. 替代方案

    • 如果不能或不想升级 MongoDB 版本,可以考虑使用其他方式来实现相同的功能。例如,可以先从数据库获取所有数据,然后在应用层面进行地理空间计算。

示例代码

使用 $geoNear 的示例(适用于 MongoDB 3.2+)

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// 假设我们有一个包含地理位置信息的集合
const locationSchema = new Schema({
    name: String,
    location: { type: { type: String }, coordinates: [] }
});

locationSchema.index({ location: '2dsphere' });

const Location = mongoose.model('Location', locationSchema);

// 使用 $geoNear 管道
Location.aggregate([
    {
        $geoNear: {
            near: { type: "Point", coordinates: [longitude, latitude] },
            distanceField: "dist.calculated",
            maxDistance: 10000,
            spherical: true
        }
    }
], (err, result) => {
    if (err) {
        console.error(err);
    } else {
        console.log(result);
    }
});

在应用层处理地理空间计算

如果无法使用 $geoNear,可以在 Node.js 中实现地理距离计算:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// 假设我们有一个包含地理位置信息的集合
const locationSchema = new Schema({
    name: String,
    location: { type: { type: String }, coordinates: [] }
});

locationSchema.index({ location: '2dsphere' });

const Location = mongoose.model('Location', locationSchema);

async function getLocationsByDistance(longitude, latitude, maxDistance) {
    const locations = await Location.find();
    const earthRadiusKm = 6371;
    const results = locations.map(location => ({
        ...location._doc,
        distance: earthRadiusKm * Math.acos(
            Math.sin(latitude * Math.PI / 180) * Math.sin(location.location.coordinates[1] * Math.PI / 180) +
            Math.cos(latitude * Math.PI / 180) * Math.cos(location.location.coordinates[1] * Math.PI / 180) *
            Math.cos((longitude - location.location.coordinates[0]) * Math.PI / 180)
        )
    })).filter(location => location.distance <= maxDistance);

    return results.sort((a, b) => a.distance - b.distance);
}

getLocationsByDistance(10, 10, 100).then(locations => console.log(locations));

这个示例展示了如何在应用层计算地理距离。请注意,这种方法不如数据库内置的地理空间查询高效,但在某些情况下可能是唯一的选择。


我一直以为$geoNear这个管道是最垃圾的,没想到还真有人用。。我估计你那是版本问题。升级版本这个还是看官方文档 吧。

另:请教楼主,我现在遇到一个问题。我有一个集合里有一个ref字段关联另一个集合,一般情况下,我用populate可以关联查询出来。 但是我现在还需要用aggregate来分组统计计算一下。。可是却不支持ref字段?怎么办呢?

从你的描述来看,这个问题可能是因为不同版本的 MongoDB 对 aggregate 操作的支持程度不同导致的。

问题分析

  • 本地环境:MongoDB 版本为 2.6.4,支持 $geoNear 操作。
  • 线上环境:MongoDB 版本为 2.2.2,不支持 $geoNear 操作。

解决方案

  1. 升级 MongoDB 版本

    • 如果可以,建议将线上环境的 MongoDB 升级到 2.6.x 或更高版本。但请注意,升级过程中可能会遇到一些兼容性问题,需要仔细测试。
  2. 修改查询逻辑

    • 如果不能升级 MongoDB 版本,可以考虑使用替代方法来实现地理空间查询功能。例如,可以在客户端进行距离计算或在服务器端使用其他方式来实现类似的功能。

示例代码

如果需要使用替代方法,以下是一个简单的示例代码,展示如何在服务器端实现距离计算:

const mongoose = require('mongoose');
const GeoJSON = require('mongoose-geojson-schema');

const LocationSchema = new mongoose.Schema({
    name: String,
    location: {
        type: GeoJSON.Point,
        index: '2dsphere'
    }
});

const Location = mongoose.model('Location', LocationSchema);

// 服务器端实现距离计算
function getLocationsByDistance(lat, lng, distance) {
    const query = {
        location: {
            $nearSphere: {
                $geometry: {
                    type: "Point",
                    coordinates: [lng, lat] // 注意坐标顺序:经度在前,纬度在后
                },
                $maxDistance: distance * 1000 // 距离(以米为单位)
            }
        }
    };

    return Location.find(query);
}

module.exports = getLocationsByDistance;

这段代码使用了 $nearSphere 查询,适用于较旧版本的 MongoDB(如 2.2.2)。虽然不如 $geoNear 灵活,但它仍然能够满足基本的地理空间查询需求。

希望这些信息对你有所帮助!

回到顶部