英文:
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 
$setWindowFieldsto set the index - Use 
$reduceto 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 
_idand then use$lookupafter the$match 
EDIT: If you want the index according to the entire sort:
- Add another output field on the 
$setWindowFieldsto set the index - Use 
$reduceto 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论