Има няколко начина да се подходи към това в рамката за агрегиране, без да се прибягва до mapReduce. Последните MongoDB 2.6 и по-нови версии имат някои оператори, които да помогнат тук, използвайки $let
и $map
за дефиниране на променлива и обработка на масива.
Вашата външна декларация изглежда по-добре за тези цели по следния начин:
var norm = [
{ "key": 1, "value": 1 },
{ "key": 2, "value": 1.16 },
{ "key": 3, "value": 1.413 },
{ "key": 4, "value": 1.622 },
{ "key": 5, "value": 1.6 },
{ "key": 6, "value": 1.753 },
{ "key": 7, "value": 3.001 },
{ "key": 8, "value": 2.818 },
{ "key": 9, "value": 3.291 },
{ "key": 10,"value": 2.824 },
{ "key": 11, "value": 2.993 },
{ "key": 12, "value": 2.699 },
{ "key": 13, "value": 1.099 },
{ "key": 14, "value": 1.035 },
{ "key": 15, "value": 1.172 },
{ "key": 16, "value": 1.013 },
{ "key": 17, "value": 0.9936 },
{ "key": 18, "value": 1.069 }
];
И след това обработете обобщения израз:
db.mycoll.aggregate([
{ "$match": {
"_id.day" : ISODate("2014-06-19T00:00:00.000Z"),
"_id.lt" : "l",
"_id.rt" : "rltdlsts",
"_id.m": false
}},
{ "$unwind": "$value.rl" },
{ "$match": { "value.rl.p": { "$gte": 1, "$lte": 18 } } },
{ "$project": {
"value": 1,
"norm": {
"$let": {
"vars": {
"norm": norm
},
"in": {
"$setDifference": [
{ "$map": {
"input": "$$norm",
"as": "norm",
"in": {
"$cond": [
{ "$eq": [ "$$norm.key", "$value.rl.p" ] },
"$$norm.value",
false
]
}
}},
[false]
]
}
}
}
}},
{ "$unwind": "$norm" }
{ "$group": {
"_id": "$value.rl.a",
"v": { "$sum": "$value.rl.v" },
"c": { "$sum": "$value.rl.c" },
"nv": { "$sum": { "$multiply": [ "$norm", "$value.rl.v" ] } }
}}
])
В този $project
етап, вие всъщност инжектирате външната декларация като променлива на масив в тръбопровода и след това обработвате всеки елемент, за да съответства на вашите съществуващи ключове "value.rl.p". Това връща само една съвпадаща стойност, така че по-нататъшното използване на $unwind
всъщност само прави резултата от масива с единичен елемент единствена стойност за използване в по-късния $group
изявление.
Традиционният подход в по-ранните версии, където операторите не се поддържат, е да се използва вложен $cond
израз за оценка на всяка стойност:
db.mycoll.aggregate([
{ "$match": {
"_id.day" : ISODate("2014-06-19T00:00:00.000Z"),
"_id.lt" : "l",
"_id.rt" : "rltdlsts",
"_id.m": false
}},
{ "$unwind": "$value.rl" },
{ "$match": { "value.rl.p": { "$gte": 1, "$lte": 18 } } },
{ "$group": {
"_id": "$value.rl.a",
"v": { "$sum": "$value.rl.v" },
"c": { "$sum": "$value.rl.c" },
"nv": { "$sum": { "$multiply": [
{ "$cond": [
{ "$eq": [ "$value.rl.p", 2 },
1.16
{ "$cond": [
{ "$eq": [ "$value.rl.p", 3 },
1.413,
{ "$cond": [
{ "$eq": [ "$value.rl.p", 4 },
1.622,
{ "$cond": [
{ "$eq": [ "$value.rl.p", 5 },
1.6,
{ "$cond": [
{ "$eq": [ "$value.rl.p", 6 },
1.753,
{ "$cond": [
{ "$eq": [ "$value.rl.p", 7 },
3.001,
{ "$cond": [
{ "$eq": [ "$value.rl.p", 8 },
2.818,
{ "$cond": [
{ "$eq": [ "$value.rl.p", 9 },
3.291,
{ "$cond": [
{ "$eq": [ "$value.rl.p", 10 },
2.824,
{ "$cond": [
{ "$eq": [ "$value.rl.p", 11 },
2.993,
{ "$cond": [
{ "$eq": [ "$value.rl.p", 12 },
2.699,
{ "$cond": [
{ "$eq": [ "$value.rl.p", 13 },
1.099,
{ "$cond": [
{ "$eq": [ "$value.rl.p", 14 },
1.035,
{ "$cond": [
{ "$eq": [ "$value.rl.p", 15 },
1.172,
{ "$cond": [
{ "$eq": [ "$value.rl.p", 16 },
1.013,
{ "$cond": [
{ "$eq": [ "$value.rl.p", 17 },
0.9936,
{ "$cond": [
{ "$eq": [ "$value.rl.p", 18 },
1.069,
1
]}
]}
]}
]}
]}
]}
]}
]}
]}
]}
]}
]}
]}
]}
]}
]}
]},
"$value.rl.v"
]}}
}}
])
Изглежда шумно, но е следващата най-ефективна форма на заявката, показана по-горе. В действителност бихте генерирали етапа на тръбопровода по начин, подобен на показан тук .