概要
例えばPostgreSQLではORDER BY句において、7.5. 行の並べ替え(ORDER BY)のドキュメントにある通り、NULLS FIRST
やNULLS LAST
で、ソートにおけるnull値の位置を設定できます。
MongoDBでは2023年11月時点においては、そのような設定は無いようです。では、null値の位置を明示的に設定するにはどうしたらよいか、というのを今回メモ書きします。
対応方針
やり方は色々考えられると思いますが、How to sort null value at the end while in Ascending MongoDBのstackoverflowの回答に書かれている内容が、良いかなと感じました。
対応方針としては、aggregateにおいてソート用のフィールドを設けて、nullの場合は$ifNull
句で後ろにくるような数値を設定し、その後ソートします。
実装サンプル
Goで実装した内容を以下に記します。Go以外でも同様のクエリで期待した結果が得られると思います。
func SampleSortQuery(userAccountId string) ([]modelDb.ResultEntity, error) {
ctx, _ := context.WithTimeout(context.Background(), 20*time.Second)
c, err := mongo.Connect(ctx, options.Client().ApplyURI(os.Getenv("DB_CONNECTION")))
col := c.Database(os.Getenv("DB_NAME")).Collection("sample_collection")
if col == nil {
panic(errors.New("can not get collection"))
}
var docs []modelDb.ResultEntity
// ここからクエリの内容
matchStage := bson.M{"$match": bson.M{
"user_account_id": userAccountId},
}
// display_orderのフィールドで基本ソートするがnullの場合は末尾にする
addSortStage := bson.M{"$addFields": bson.M{
"sort_field": bson.M{"$ifNull": bson.A{"$display_order", math.MaxInt32}}},
}
sortStage := bson.M{"$sort": bson.M{
"sort_field": 1},
}
projectStage := bson.M{"$project": bson.M{
"_id": 1,
"name": 1,
"description": 1,
}}
cur, err := col.Aggregate(context.Background(),
[]bson.M{
matchStage, addSortStage, sortStage, projectStage,
})
if err != nil {
return docs, err
}
for cur.Next(context.Background()) {
var doc modelDb.ResultEntity
if err = cur.Decode(&doc); err != nil {
return nil, err
}
docs = append(docs, doc)
}
return docs, nil
}