MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

mongodb:interroga le prime righe in cui la somma di una colonna specifica è maggiore o uguale a C

Interroga

Potrebbe essere fatto utilizzando framework di aggregazione . Considera la prossima sezione di aggregazione

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

Risultati

Spiegazione

L'idea di base è quella di costruire array di supporto per ogni documento della raccolta (fasi 1-3 )

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

utilizzando $slice operatore di aggregazione di array e quindi sostituirlo con la somma di tutti gli elementi che contiene (fasi 4-5 )

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

utilizzando $unwind stage e $sum operatore accumulatore di gruppo .

Quindi costruisci un altro array di documenti di supporto con csum >= C (fase 6 )

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

L'ultimo passaggio consiste nel recuperare tutti i documenti con csum <= Min { gteC.csum } . Questo viene fatto utilizzando $filter operatore di aggregazione di array (fase 7 ).

Tuttavia, io non certo che questo è il più efficiente pipeline di aggregazione (sarò grato per eventuali suggerimenti di miglioramento) per ottenere ciò che desideri.

PS Prima di testare la query non dimenticare di cambiare il nome della raccolta e di sostituire SET_DESIRED_VALUE_FOR_C_HERE.