MongoDB聚合运算符:$sortArray
$sortArray
聚合运算符根据指定的排序规则对数组元素进行排序。
语法
$sortArray: {
input: <array>,
sortBy: <sort spec>
}
input
:为可解析为数组的表达式,如果表达式字段缺失、为null或undefined,则返回null,如果表达式为其他非数组的值,则返回错误。sortBy
:文档类型,用于指定排序方式。
使用
$sortArray
表达式根据sortBy
规范对输入数组进行排序。$sortArray
的语法和语义与通过$sort
修改的$push
操作中的行为相同。
根据文档字段进行排序
如果数组元素是文档,则可以按文档字段排序,指定字段名称和排序方向:升序 (1
) 或降序 (-1
)。
{
input: <array-of-documents>,
sortBy: { <document-field>: <sort-direction> }
}
根据值排序
要按值对整个数组进行排序,或按非文档的数组元素进行排序,需要指定输入数组并在 sortBy
参数中指定 1
表示升序排序,或指定 -1
表示降序排序。
{
input: <array-of-documents>,
sortBy: <sort-direction>
}
注意事项
- 对于排序的键值,不会进行隐式数组遍历。
- 不支持位置运算符,像
"values.1"
这样的字段名称表示value
数组中名为"1"
的子字段,而不是引用数组中的第1
个元素。 - 当整个数组排序时,排序按字典顺序,与聚合
$sort
阶段的行为有所不同。 - 当数组按字段排序时,任何不具有指定字段的文档或标量会被平均排序,也就是结果的排序顺序不确定。
null
和缺失值按照同等顺序排序。$sortArray
的排序是不稳定的,不应依赖其排序算法的稳定性。
举例
使用下面的脚本创建team
集合:
db.engineers.insertOne(
{
"team":
[
{
"name": "pat",
"age": 30,
"address": { "street": "12 Baker St", "city": "London" }
},
{
"name": "dallas",
"age": 36,
"address": { "street": "12 Cowper St", "city": "Palo Alto" }
},
{
"name": "charlie",
"age": 42,
"address": { "street": "12 French St", "city": "New Brunswick" }
}
]
}
)
team
数组包含三个元素,其每个元素都有嵌套的子元素:姓名name
、年龄age
和地址address
。下面的例子演示如何使用这些子元素对 team
数组进行排序。
根据字段排序
根据指定的字段对数组元素进行排序:
db.engineers.aggregate( [
{ $project:
{
_id: 0,
result:
{
$sortArray: { input: "$team", sortBy: { name: 1 } }
}
}
}
] )
name
字段是team
数组的子元素,操作返回以下结果::
{
result:
[
{
name: 'charlie',
age: 42,
address: { street: '12 French St', city: 'New Brunswick' }
},
{
name: 'dallas',
age: 36,
address: { street: '12 Cowper St', city: 'Palo Alto' }
},
{
name: 'pat',
age: 30,
address: { street: '12 Baker St', city: 'London' }
}
]
}
根据子字段排序
address
字段是文档的子字段,使用点号.
根据子字段对数组进行排序:
db.engineers.aggregate( [
{
$project:
{
_id: 0,
result:
{
$sortArray:
{
input: "$team",
sortBy: { "address.city": -1 }
}
}
}
}
] )
由于 sortBy
值为-1
,因此排序方向为降序,结果如下:
{
result: [
{
name: 'dallas',
age: 36,
address: { street: '12 Cowper St', city: 'Palo Alto' }
},
{
name: 'charlie',
age: 42,
address: { street: '12 French St', city: 'New Brunswick' }
},
{
name: 'pat',
age: 30,
address: { street: '12 Baker St', city: 'London' }
}
]
}
根据多个字段排序
指定多个索引字段进行复合排序:
db.engineers.aggregate( [
{
$project:
{
_id: 0,
result:
{
$sortArray:
{
input: "$team",
sortBy: { age: -1, name: 1 }
}
}
}
}
] )
操作返回以下结果::
{
name: 'charlie',
age: 42,
address: { street: '12 French St', city: 'New Brunswick' }
},
{
name: 'dallas',
age: 36,
address: { street: '12 Cowper St', city: 'Palo Alto' }
},
{
name: 'pat',
age: 30,
address: { street: '12 Baker St', city: 'London' }
}
对整数数组排序
本例直接指定了一个输入数组,所有值的类型都是Int32
:
db.engineers.aggregate( [
{
$project:
{
_id: 0,
result:
{
$sortArray:
{
input: [ 1, 4, 1, 6, 12, 5 ],
sortBy: 1
}
}
}
}
] )
输入数组的第 0
位和第 2
位都有一个 "1"
。在结果中,"1"
会被分组,但并不保证 "1"
组的排序与原始顺序一致。
操作返回以下结果::
[ { result: [ 1, 1, 4, 5, 6, 12 ] } ]
对混合类型字段进行排序
本例直接指定一个输入数组,这些值有不同的类型:
db.engineers.aggregate( [
{
$project:
{
_id: 0,
result:
{
$sortArray:
{
input: [ 20, 4, { a: "Free" }, 6, 21, 5, "Gratis",
{ a: null }, { a: { sale: true, price: 19 } },
Decimal128( "10.23" ), { a: "On sale" } ],
sortBy: 1
}
}
}
}
] )
name
字段是team
数组的子元素,操作返回以下结果::
{ result: [
4,
5,
6,
Decimal128("10.23"),
20,
21,
'Gratis',
{ a: null },
{ a: 'Free' },
{ a: 'On sale' },
{ a: { sale: true, price: 19 } }
] }
结果是有序的。相反,将 sortBy
字段改为根据文档字段之一(sortBy: { a: 1 }
排序后,标量值和空值的排序顺序未定义:
{ result: [
20,
4,
6,
21,
5,
'Gratis',
{ a: null },
Decimal128("10.23"),
{ a: 'Free' },
{ a: 'On sale' },
{ a: { sale: true, price: 19 } }
] }