Kueri
Itu bisa dilakukan dengan menggunakan kerangka agregasi . Pertimbangkan pipa agregasi berikutnya
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) */
]);
Hasil
Penjelasan
Ide dasar di baliknya adalah untuk membangun array pembantu untuk setiap dokumen dalam koleksi (tahap 1-3 )
{ "_id" : 1, "c" : 2 } -> cs = [ 2 ]
{ "_id" : 2, "c" : 6 } -> cs = [ 2, 6 ]
{ "_id" : 3, "c" : 1 } -> cs = [ 2, 6, 1 ]
menggunakan $slice
operator agregasi array lalu ganti dengan jumlah semua elemen yang dikandungnya (tahap 4-5 )
{ "_id" : 1, "c" : 2 } -> csum = 2
{ "_id" : 2, "c" : 6 } -> csum = 8
{ "_id" : 3, "c" : 1 } -> csum = 9
menggunakan $unwind
stage dan $sum
operator akumulator grup .
Kemudian buat susunan dokumen pembantu lain dengan csum >= C
(tahap 6 )
/* Ex. (C = 8) */
gteC = [ { "_id" : 3, "c" : 1, "csum" : 9 }, { "_id" : 2, "c" : 6, "csum" : 8 } ]
Langkah terakhir adalah mengambil semua dokumen dengan csum <= Min { gteC.csum }
. Ini dilakukan menggunakan $filter
operator agregasi array (tahap 7 ).
Namun, saya tidak yakin ini yang paling efisien pipa agregasi (akan berterima kasih atas saran peningkatan apa pun) untuk mencapai apa yang Anda inginkan.
PS Sebelum menguji kueri, jangan lupa untuk mengubah nama koleksi dan mengganti SET_DESIRED_VALUE_FOR_C_HERE.