繁体   English   中英

mongodb:查询特定列的总和大于或等于C的前几行

[英]mongodb: query first few rows where sum of specific column is greater or equal than C

假设我们有一个包含2列的mongodb集合:id,c

1,2
2,6
3,1
...

现在我想选择列c的总和大于或等于C前几行

在上述情况下,如果C = 1,则返回前1行。 如果C = 8,则返回前2行。 如果C = 9,则返回前3行。

询问

可以使用聚合框架来完成。 考虑下一个聚合管道

db.collectionName.aggregate([
  {
    $group: 
      { 
        "_id": null, 
        "ds": { $push: "$$ROOT" }, 
        "cs": { $push: "$c" } 
      } 
  }, /* (1) */
  { $unwind: "$ds" }, /* (2) */
  { 
    $project: 
      { 
        "_id": "$ds._id", 
        "c": "$ds.c", 
        "cs": { $slice: [ "$cs", "$ds._id" ] } 
      } 
  }, /* (3):  */
  { $unwind: "$cs" },  /* (4) */
  { 
    $group: 
      { 
        "_id": "$_id", 
        "c": { $first: "$c" }, 
        "csum": { $sum: "$cs" } 
      } 
  }, /* (5) */
  { 
    $group: 
      { 
        "_id": null, 
        "ds": { $push: "$$ROOT" }, 
        "gteC": 
          { 
            $push: 
              { 
                $cond: 
                  { 
                    if: { "$gte": [ "$csum", SET_DESIRED_VALUE_FOR_C_HERE ] }, 
                    then: "$$ROOT", 
                    else: { } 
                  } 
              } 

          } 
      } 
  }, /* (6) */
  { 
    $project: 
      { 
        "_id": 0,
        "docs": 
          { 
            $filter: 
              { 
                input: "$ds", 
                "as": "doc", 
                cond: { $lte: [ "$$doc.csum", { $min: "$gteC.csum" } ] }
              }
          }
      }
  }, /* (7) */
  { $unwind: "$docs" }, /* (8) */ 
  { $project: { "_id": "$docs._id", "c": "$docs.c" } } /* (9) */
]);

结果

C = 1 => { "_id": 1, "c": 2 }

C = 8 => [ { "_id": 2, "c": 6 }, { "_id": 1, "c": 2 } ]

C = 9 => [ { "_id": 3, "c": 1 }, { "_id": 2, "c": 6 }, { "_id": 1, "c": 2 } ]

C = 10 =>

说明

它背后的基本思想是为集合中的每个文档构建辅助数组阶段1-3

{ "_id" : 1, "c" : 2 } -> cs = [ 2 ]
{ "_id" : 2, "c" : 6 } -> cs = [ 2, 6 ]
{ "_id" : 3, "c" : 1 } -> cs = [ 2, 6, 1 ]

使用$slice 数组聚合运算符 ,然后用它包含的所有元素的总和替换它( 阶段4-5

{ "_id" : 1, "c" : 2 } -> csum = 2
{ "_id" : 2, "c" : 6 } -> csum = 8
{ "_id" : 3, "c" : 1 } -> csum = 9

使用$unwind stage和$sum group accumulator operator

然后使用csum >= C构建另一个文档辅助数组( 阶段6

/* Ex. (C = 8) */
gteC = [ { "_id" : 3, "c" : 1, "csum" : 9 }, { "_id" : 2, "c" : 6, "csum" : 8 } ]

最后一步是使用csum <= Min { gteC.csum }检索所有文档。 这是使用$filter 数组聚合运算符第7阶段 )完成的。

不过,我知道这是最有效的聚集管道(将是任何改进的建议表示感谢),以达到你想要什么。

PS在测试查询之前,不要忘记更改集合的名称并替换SET_DESIRED_VALUE_FOR_C_HERE。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM