如何在Java项目中基于Morphia实现MongoDB数据的大小写不敏感排序
解决Morphia排序忽略大小写的问题
我之前也碰到过一模一样的场景,Morphia默认的ASCII排序确实会把小写开头的内容排在大写前面,完全不符合业务里自然排序的预期。这里有两个靠谱的方案,你可以根据自己的情况选:
方案一:使用MongoDB的Collation(推荐)
MongoDB 3.4+支持Collation功能,可以指定排序时忽略大小写,Morphia也提供了对应的API来配置这个。你只需要在查询里添加Collation设置,指定强度为2(忽略大小写)就行。
修改你的代码如下:
Query<MyObject> query = store.query(MyObject.class); query = query.field("myfield").equal("some value"); // 设置collation,忽略大小写排序 query.collation(Collation.builder().locale("en").collationStrength(CollationStrength.SECONDARY).build()); query.order("myfield"); List<MyObject> result = query.asList();
这里的CollationStrength.SECONDARY会让MongoDB在排序时忽略大小写差异,同时保留重音符号的区分(如果不需要的话可以用TERTIARY,不过一般业务场景用SECONDARY足够)。这个方案是MongoDB原生支持的,性能最好,不需要额外的字段或处理。
方案二:投影转换字段后排序(备选)
如果你的MongoDB版本比较旧,不支持Collation的话,可以考虑在查询时把目标字段转成小写(或大写),然后按转换后的字段排序。不过这种方法需要额外的投影操作,而且如果数据量大的话可能会影响性能,不如第一种方案高效。
示例代码:
// 先投影出转换后的字段,再按该字段排序 Query<MyObject> query = store.query(MyObject.class) .field("myfield").equal("some value") .project("lowerMyfield", Projection.expression("toLowerCase", "$myfield")) .order("lowerMyfield"); List<MyObject> result = query.asList();
注意这种方法返回的结果里会包含lowerMyfield这个投影字段,如果不需要的话可以后续过滤掉,或者使用projection.exclude来排除它。
另外,如果你经常需要按这个字段忽略大小写排序,也可以考虑给转换后的字段建立索引,这样能提升排序的性能,但会增加存储和写入的开销,需要权衡。
内容的提问来源于stack exchange,提问作者Daneel




