MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

mongodb :interroge les premières lignes où la somme d'une colonne spécifique est supérieure ou égale à C

Requête

Cela pourrait être fait en utilisant le cadre d'agrégation . Envisagez le prochain pipeline d'agrégation

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) */
]);

Résultats

Explication

L'idée de base derrière cela est de construire un tableau d'aide pour chaque document de la collection (étapes 1 à 3 )

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

en utilisant $slice opérateur d'agrégation de tableaux puis remplacez-le par la somme de tous les éléments qu'il contient (étapes 4-5 )

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

en utilisant $unwind étape et $sum opérateur d'accumulateur de groupe .

Construisez ensuite un autre tableau d'assistance de documents avec csum >= C (étape 6 )

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

La dernière étape consiste à récupérer tous les documents avec csum <= Min { gteC.csum } . Ceci est fait en utilisant $filter opérateur d'agrégation de tableaux (étape 7 ).

Cependant, je ne suis pas sûr que c'est le plus efficace pipeline d'agrégation (sera reconnaissant pour toute suggestion d'amélioration) pour obtenir ce que vous voulez.

PS Avant de tester la requête, n'oubliez pas de changer le nom de la collection et de remplacer SET_DESIRED_VALUE_FOR_C_HERE.