The 'cursor' option is required, except for aggregate with the explain argument 错误处理

在将mysql转为mongoDB的过程中遇到geoNear查询问题,报错'The 'cursor' option is required...'。通过分析发现,从3.6版本后aggregate查询需使用Cursor接收结果。解决方案是在调用aggregate方法时设置AggregationOptions的输出模式为Cursor。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景:

最近开始做mongoDB,公司原有的mysql数据库需要在短期内转库为mongoDB,在重构代码过程中,旧有的一些业务逻辑就需要改动了。比较棘手的,就是地理位置数据做排序,这一点上,我打算用mongoDB的geoNear经纬度查询功能来实现。

 

经过:

在mongoDB中,我写了一段nosql,可以按输入的定点位置以经纬度排序:

db.getCollection("projectInternalUseData").aggregate({
    $geoNear: {
        near: [100.0, 50.0],
        distanceField: "calculated",
        spherical: true
   }
})

上诉代码能正常运行,需要几个条件:

1. projectInternalUseData集合必须有一个 2d 经纬索引

2.该索引的字段,必须存放一个数组作为坐标:[ x , y ]

建立索引语句如下:

db.getCollection("projectInternalUseData").createIndex({ "trueCoordinates" , "2dsphere" });

旧版本(3.4以下)是用 ensureIndex 函数的

 

经过上述测试,nosql查询无误,数据没问题,下一步,在java中实现查询,

这里用的是spring-data-mongodb,有关maven配置就不赘述了

代码如下:

List<DBObject> list = new LinkedList<>();
List<DBObject> pipeLine = new ArrayList<>();
BasicDBObject aggregate = new BasicDBObject("$geoNear",
      new BasicDBObject("near",new double[]{point.getX(), point.getY()})
           .append("distanceField","calculated")
           //.append("query", new BasicDBObject())
           //.append("maxDistance", 5000)
           .append("spherical",true)
);
pipeLine.add(aggregate);
Cursor cursor = mongoTemplate.getCollection("projectInternalUseData")
      .aggregate(pipeLine, AggregationOptions.builder().build());
while (cursor.hasNext()) {
    list.add(cursor.next());
}

System.out.println("查询结果:" + list.size());
for ( DBObject obj : list ){
     System.out.println( obj );
}

运行测试,报出错误:“The 'cursor' option is required, except for aggregate with the explain argument 

 

 

解决:

英语能力有限,简单地翻译,这个异常提示是:选项光标不可缺失,除非aggregete带上了解释参数。

于是,我先百度,谷歌,看看其他博客的方案:

1. 提升版本,将mongoDB版本回退到 3.2 < 已回退过,没用,排除 >

2. 需要用Cursor来接收结果,不能像find函数那样直接得到List集合 < 我的代码就是用Cursor接收的,没用 >

 

既然以上方法都没用,那就关注一个点:Cursor是个什么东西,一定是这个东西导致异常

查询mongoDB的API,有如下结果:

按上面的意思,cursor是用来接收document返回结果的,按理说,我的代码是没问题的。

但是,既然这是从3.6之后更变过,那就说明,在此之前,原本document是可以封装成List集合来得到结果的,

从那之后,需要用cursor来接收,而现阶段,find函数依旧保留List集合的类型返回,那就说明,aggregate( pipeline,options) 方法执行时有问题,进入该方法,并设置断点:

debug模式开启后,断点最终定在上图541行代码,

也就是this.executor.execute( operation, readPreference );

而能涉及到Cursor的,就在540这一行代码:

AggregateOperation<DBObject> operation = (
    new AggregateOperation(
        this.getNamespace(), stages, this.getDefaultDBObjectCodec() 
    )
).readConcern( this.getReadConcern() ).
maxTime( options.getMaxTime( TimeUnit.MILLISECONDS ),TimeUnit.MILLISECONDS ).
allowDiskUse( options.getAllowDiskUse() ).
batchSize( options.getBatchSize() ).
useCursor( options.getOutputMode() == OutputMode.CURSOR );

operation的初始化,伴随着一大串options参数对象的链式追加,每一个追加方法,都返回了一个operation对象。

在最后一个 .useCursor( true / false ); 方法中,终于看到了 CURSOR字样,

并且,由options.getOutputMode() 方法名可以得出:参数对象 options可以切换输出输出模式

默认的模式,是List集合输出,当输出模式转换为 OutjputMode.CURSOR时,意味着此时才能用Cursor对象来接收结果。

 

改正:

那么,对应aggregate( List<?> pipeLine , AggregationOptions options, ReadReference readReference    )方法,

只需要在传入options参数前,给该参数设置好输出模式为CURSOR就可以了:

执行结果:

异常解决

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值