Очень интересный вопрос. Возможно, существует какое-то лучшее решение.
Отказ от ответственности : я предполагаю, что пользовательские баллы уникальны
Мы можем использовать $ facet , чтобы получить ожидаемый результат, но высокая стоимость (очень большой запрос)
db.collection.aggregate([
{
$facet: {
"givenUser": [
{
$match: {
"user": "C"
}
}
],
"allUser": [
{
$sort: {
"Points": -1
}
}
],
"orderedPoints": [
{
$sort: {
"Points": -1
}
},
{
$group: {
_id: null,
Points: {
$push: "$Points"
}
}
},
{
$unwind: "$Points"
}
]
}
},
{
$project: {
allUser: 1,
currIndex: {
$indexOfArray: [
"$orderedPoints.Points",
{
$arrayElemAt: [
"$givenUser.Points",
0
]
}
]
},
beforeIndex: {
$add: [
{
$indexOfArray: [
"$orderedPoints.Points",
{
$arrayElemAt: [
"$givenUser.Points",
0
]
}
]
},
-1
]
},
afterIndex: {
$add: [
{
$indexOfArray: [
"$orderedPoints.Points",
{
$arrayElemAt: [
"$givenUser.Points",
0
]
}
]
},
1
]
}
}
},
{
$project: {
result: [
{
$arrayElemAt: [
"$allUser",
{
$cond: {
if: {
$lt: [
"$beforeIndex",
0
]
},
then: 999,
else: "$beforeIndex"
}
}
]
},
{
$arrayElemAt: [
"$allUser",
"$currIndex"
]
},
{
$arrayElemAt: [
"$allUser",
"$afterIndex"
]
}
]
}
}
])
[
{
"result": [
{
"Points": 22,
"_id": ObjectId("5a934e000102030405000000"),
"user": "A"
},
{
"Points": 15,
"_id": ObjectId("5a934e000102030405000002"),
"user": "C"
},
{
"Points": 11,
"_id": ObjectId("5a934e000102030405000001"),
"user": "B"
}
]
}
]
MongoPlayground
Шаги:
Мы держим в отдельных полях:
- Данный пользователь (C),
- Заказ всех пользователей по точкам
- Заказ всех точек и хранение внутримассив (хотелось бы, чтобы MongoDB также позволял находить индекс массива по объектам)
Теперь мы находим заданный индекс пользователя, рассчитываем индексы для игроков «до» / «после».
Теперь мы создаем результат с 3 элементами (до, текущий, после).
Примечание: Если данный пользователь является первым / последним, мы гарантируем возврат null
для элементов до / после.