升级ReactiveMongo 0.13.0后聚合查询报DefaultJSONCommandError
针对你升级ReactiveMongo到0.13.0-play26后聚合查询报错的问题,结合你提供的代码、报错信息和Mongo CLI的测试结果,我整理了几个关键排查方向,你可以逐一验证:
1. 调整聚合API的调用方式
ReactiveMongo 0.13.x对聚合API做了版本迭代,你之前将Match单独作为第一个参数的写法,在新版本中可能不再被支持。尝试把Match阶段合并到后续的Pipeline列表中:
col .aggregate( List( Match(Json.obj("obj" -> Json.obj("$in" -> ids.map(_.toString)))), Sort(Descending("lm")), Group(JsString("$obj"))("obj" -> FirstField("obj"), "ts" -> FirstField("lm")), Project(Json.obj("_id" -> 0, "obj" -> "$obj", "ts" -> "$ts")) ) ) .map(_.head[Bar])
旧版本可能支持aggregate(query: BSONDocument, pipeline: List[PipelineStage])的重载,但0.13.x大概率统一要求所有阶段都放入同一个Pipeline列表。
2. 排查UUID类型的匹配逻辑
你的Foo类中obj是UUID类型,得先确认Mongo里存储的是UUID二进制类型还是字符串类型:
- 如果Mongo中存的是UUID二进制(BSON Binary subtype 0x04),那你用字符串形式的
$in查询可能无法匹配——升级前ReactiveMongo可能自动做了字符串到UUID的隐式转换,但新版本移除了这个行为。 - 可以尝试把查询条件改成使用BSON UUID类型:
import reactivemongo.bson.BSONBinary import reactivemongo.bson.Subtype.UuidSubtype Match(Json.obj("obj" -> Json.obj("$in" -> ids.map(uuid => BSONBinary(uuid.toByteArray, UuidSubtype)))))
如果用的是JSONCollection,还要确保项目中有正确的隐式Format[UUID]来处理UUID的序列化。
3. 检查Bar类的JSON/BSON映射是否正常
报错信息里返回的文档{"obj":"a797ec90-80d7-4b5e-b144-2454436f2b16","ts":1526390247074}其实是正确结果,但被包装成了CommandError,很大概率是自动映射Bar类时失败:
- 确认你有正确的隐式
Format[Bar]或Reader[Bar],尤其是ts字段——Mongo返回的是时间戳数值,需要正确转换为Date类型。 - 可以先手动解析结果,替代
.head[Bar]来排查问题:
.map { cursor => cursor.headOption.map { case Some(jsObj) => val obj = UUID.fromString((jsObj \ "obj").as[String]) val ts = new Date((jsObj \ "ts").as[Long]) Bar(obj, ts) case None => throw new RuntimeException("No matching result found") } }
如果手动解析成功,说明是自动映射的隐式格式缺失或配置有问题。
4. 简化Group阶段的字段定义
你当前的Group阶段同时用FirstField("obj")获取obj,但其实_id已经是$obj,可以简化这个阶段,减少潜在的映射冲突:
Group(JsString("$obj"))("ts" -> FirstField("lm")) // 对应的Project阶段改为: Project(Json.obj("_id" -> 0, "obj" -> "$_id", "ts" -> "$ts"))
这样既减少了冗余字段,也避免了重复获取obj可能带来的类型不一致问题。
5. 对比实际发送的聚合命令
开启ReactiveMongo的DEBUG日志,查看实际发送给MongoDB的聚合命令,和你在CLI中执行的命令做对比:
- 检查字段名、UUID格式、Pipeline阶段顺序是否完全一致。
- 如果发现命令有差异(比如UUID被转成了错误类型、阶段缺失等),就能直接定位到API使用的具体问题。
内容的提问来源于stack exchange,提问作者schub

