获取文档的中间部分如何?

huangapple go评论59阅读模式
英文:

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:

  1. Add another output field on the $setWindowFields to set the index
  2. 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:

  1. Add another output field on the $setWindowFields to set the index
  2. 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

huangapple
  • 本文由 发表于 2023年4月20日 08:06:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76059643.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定