想不出比为集合中具有有序列表的每个文档创建一个附加数组字段更好的方法了。展开该字段并使用运算符的includeArrayIndex
属性$unwind
来生成索引位置。然后使用该信息对文档进行排序,使用附加的三元运算符$cond
评估逻辑表达式array element === coreId
,并根据结果,如果为真则返回排序索引,否则返回一个常量n > order.length
。
下面显示了上述方法,虽然还有很大的改进空间,但至少应该给你一些方向。当然,您可以将管道转换为适当的驱动程序语言(我假设是 PHP):
var order = [20, 10];
db.records.aggregate([
{
"$project": {
"coreId" : 1,
"name" : 1,
"sortOrder": { "$literal": order } // create an additional field
}
},
{
"$unwind": {
// flatten the above array
"path": "$sortOrder",
// create the index position for each array element
"includeArrayIndex": "sortIndex",
}
},
{
"$project": {
"coreId": 1,
"name": 1,
"sortIndex": {
"$cond": [
{ "$eq": [ "$coreId", "$sortOrder" ] },
"$sortIndex", 999999
]
}
}
},
{ "$sort": { "sortIndex": 1 } },
{
"$group": {
"_id": "$coreId",
"name": { "$first": "$name" },
"index": { "$first": "$sortIndex" }
}
},
{ "$sort": { "index": 1 } },
{
"$project": {
"_id": 0,
"coreId" : "$_id",
"name" : 1
}
}
])
样本结果
/* 1 */
{
"name" : "a",
"coreId" : 20
}
/* 2 */
{
"name" : "a",
"coreId" : 10
}
/* 3 */
{
"name" : "a",
"coreId" : 30
}