如何在MongoDB中对百万级carrier数组按name字段进行字母数字排序
问题:我在MongoDB中有一个包含1000000个元素的carrier数组,如何按name字段对carrier数组进行字母数字排序
对应文档存储结构示例:{ "_id" : 1, "arraySize" : 1000000, "carrier" : [ {"name" : "AB"}, {"name" : "AD"}, {"name" : "CD"}, {"name" : "DC"}, {"name" : "ZY"} ] }
实现方案
以下分两种常用场景给出对应实现方式:
场景1:查询时临时返回排序后的数组(不修改源文档)
使用MongoDB聚合管道实现,代码如下:
db.你的集合名.aggregate([ // 匹配你需要查询的目标文档,这里以_id=1为例 { $match: { _id: 1 } }, // 拆分carrier数组为单条文档 { $unwind: "$carrier" }, // 按name字段排序,1为升序,-1为降序 { $sort: { "carrier.name": 1 } }, // 重新聚合为数组 { $group: { _id: "$_id", arraySize: { $first: "$arraySize" }, carrier: { $push: "$carrier" } }} ], // 百万级数组排序会超出聚合默认100MB内存限制,开启磁盘使用权限 { allowDiskUse: true })
如果需要处理字母数字混合的自然排序(例如避免出现A10排在A2前面的问题),在管道后追加collation配置即可:
db.你的集合名.aggregate([ // 上述管道步骤不变 ], { allowDiskUse: true, collation: { locale: "en", numericOrdering: true } })
场景2:永久更新源文档的carrier数组为排序后状态
适用于MongoDB 5.2及以上版本
使用原生$sortArray运算符实现,性能更高:
db.你的集合名.updateOne( { _id: 1 }, [ { $set: { carrier: { $sortArray: { input: "$carrier", sortBy: { "name": 1 } } } } } ], // 需自然排序则打开以下配置 // collation: { locale: "en", numericOrdering: true } )
适用于所有MongoDB版本
使用$push搭配$sort修饰符实现:
db.你的集合名.updateOne( { _id: 1 }, { $push: { carrier: { $each: [], $sort: { name: 1 } } } }, // 需自然排序则打开以下配置 // collation: { locale: "en", numericOrdering: true } )
注意事项
- 百万级数组的排序和更新属于重资源操作,建议在业务低峰期执行,避免影响线上业务
- 执行更新操作前建议先备份对应文档,避免误操作导致数据丢失
内容的提问来源于stack exchange,提问作者Chetan Parmar
相关产品推荐
相关产品推荐

