Consulta
Se podría hacer usando marco de agregación . Considere la próxima canalización de agregación
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) */
]);
Resultados
Explicación
La idea básica detrás de esto es construir matriz auxiliar para cada documento de la colección (etapas 1-3 )
{ "_id" : 1, "c" : 2 } -> cs = [ 2 ]
{ "_id" : 2, "c" : 6 } -> cs = [ 2, 6 ]
{ "_id" : 3, "c" : 1 } -> cs = [ 2, 6, 1 ]
usando $slice
operador de agregación de matriz y luego reemplácelo con la suma de todos los elementos que contiene (etapas 4-5 )
{ "_id" : 1, "c" : 2 } -> csum = 2
{ "_id" : 2, "c" : 6 } -> csum = 8
{ "_id" : 3, "c" : 1 } -> csum = 9
usando $unwind
escenario y $sum
operador acumulador de grupo .
Luego construya otra matriz auxiliar de documentos con csum >= C
(etapa 6 )
/* Ex. (C = 8) */
gteC = [ { "_id" : 3, "c" : 1, "csum" : 9 }, { "_id" : 2, "c" : 6, "csum" : 8 } ]
El último paso es recuperar todos los documentos con csum <= Min { gteC.csum }
. Esto se hace usando $filter
operador de agregación de matriz (etapa 7 ).
Sin embargo, no seguro que este es el más eficiente tubería de agregación (agradeceremos cualquier sugerencia de mejora) para lograr lo que desea.
PD Antes de probar la consulta, no olvide cambiar el nombre de la colección y reemplazar SET_DESIRED_VALUE_FOR_C_HERE.