英文:
How to get the middle of documents?
问题
如何在mongoose中获取文档的中间部分?
集合模式:
{
_id: string,
points: number
}
我想按照points进行排序,然后按照_id进行匹配,最终结果获取前50个和后50个,以匹配的_id作为中心。如果可以的话,还可以包括基于排序的索引,但不是必需的。
英文:
How do I get the middle of documents in mongoose?
Collection Schema:
{
_id: string,
points: number
}
I want to sort by points, then match by _id, and the end result grabs the top 50, and bottom 50, with matched _id as the center. Also includes the index based on the sort would be nice but not necessary.
答案1
得分: 3
One option since mongodb version 5.0 is to use $setWindowFields
:
db.collection.aggregate([
{$setWindowFields: {
sortBy: {points: -1},
output: {
neighbors: {
$push: "$$ROOT",
window: {documents: [-N, N]}
}
}
}},
{$match: {_id: _id}},
{$project: {neighbors: 1, _id: 0}},
{$unwind: {path: "$neighbors", includeArrayIndex: "index"}},
{$project: {
_id: "$neighbors._id",
points: "$neighbors.points",
index: 1
}}
])
See how it works on the playground example
If the documents are heavy, or N is a large number, you can push only the _id
and then use $lookup
after the $match
EDIT: If you want the index according to the entire sort:
- Add another output field on the
$setWindowFields
to set the index - Use
$reduce
to set the index to all items that we use
db.collection.aggregate([
{$setWindowFields: {
sortBy: {points: -1},
output: {
neighbors: {
$push: "$$ROOT",
window: {documents: [-N, N]}
},
index: {
$sum: 1,
window: {documents: ["unbounded", "current"]}
}
}
}},
{$match: {_id: _id}},
{$project: {
neighbors: {$reduce: {
input: "$neighbors",
initialValue: [],
in: {$concatArrays: [
"$$value",
[{$mergeObjects: [
"$$this",
{index: {$add: [
{$subtract: [
{$size: "$$value"}, {$min: [N + 1, "$index"]}
]},
"$index"
]}
]}]
]}
}},
_id: 0
}},
{$unwind: "$neighbors"},
{$replaceRoot: {newRoot: "$neighbors"}}
])
See how it works on the playground example
英文:
One option since mongodb version 5.0 is to use $setWindowFields
:
db.collection.aggregate([
{$setWindowFields: {
sortBy: {points: -1},
output: {
neighbors: {
$push: "$$ROOT",
window: {documents: [-N, N]}
}
}
}},
{$match: {_id: _id}},
{$project: {neighbors: 1, _id: 0}},
{$unwind: {path: "$neighbors", includeArrayIndex: "index"}},
{$project: {
_id: "$neighbors._id",
points: "$neighbors.points",
index: 1
}}
])
See how it works on the playground example
- If the documents are heavy, or N is a large number, you can push only the
_id
and then use$lookup
after the$match
EDIT: If you want the index according to the entire sort:
- Add another output field on the
$setWindowFields
to set the index - Use
$reduce
to set to index to all items that we use
db.collection.aggregate([
{$setWindowFields: {
sortBy: {points: -1},
output: {
neighbors: {
$push: "$$ROOT",
window: {documents: [-N, N]}
},
index: {
$sum: 1,
window: {documents: ["unbounded", "current"]}
}
}
}},
{$match: {_id: _id}},
{$project: {
neighbors: {$reduce: {
input: "$neighbors",
initialValue: [],
in: {$concatArrays: [
"$$value",
[{$mergeObjects: [
"$$this",
{index: {$add: [
{$subtract: [
{$size: "$$value"}, {$min: [N + 1, "$index"]}
]},
"$index"
]}}
]}]
]}
}},
_id: 0
}},
{$unwind: "$neighbors"},
{$replaceRoot: {newRoot: "$neighbors"}}
])
See how it works on the playground example
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论