Стварэнне каналаваў аграгацыі MongoDB з $match, $group і $lookup
Дазвольце даклэ научыцца, як стадіі аграгацыі MongoDB фільтруюць, групаваюць, перакаштовваюць, спаўнююць і сортаваюць дакументы, а таксама як ўжоўваць іх у ланцужку для стварэння пайплайна, які адпавядае на рэальныя запитанні з аналізу дадзеных.
Звычный запит find() падходзіць для адчынення дакументаў, якія падпадаюць пад адзін умова, але ён не можа падсумаваць выручку за кожным кліентам, прыўязаць дакладныя ведамасці аб корыстніку да замовленняў чы выдаць адчыненныя звіты. Для гэтага MongoDB праследжвае фрэймворк аграгацыі. У гэтым кяле пояснююцца пяць стадзій, якія вы будете вжываць чыстаюча, маленькія падступы ў кожной з іх і як іх спаўніць у адну лінію обробкі, якая дае чысты, гатовы до вжывання рэзультат.
Як працюе лінія аграгацыі
Аграгацыя — это абарраны список стадзій. Дакументы прайходзяць у першую стадію, кожная стадія трансфармавае поток у адны конкрэтны спосаб, і тое, што яна выдае, стае вхідным дадзеннем для наступной стадіі. Адносіцься да гэтага як да лініі зборкі дадзенняў дапамагае легка разумець порядак стадзій.
Короткая лінія обробкі нижэй залучае толькі завершаныя замовленні, падсумаввае суму за кожным кліентам і выклікае самых большых спаканаўцоў першымі.
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $group: { _id: "$customerId", total: { $sum: "$amount" } } },
{ $sort: { total: -1 } }
]);
У наступных раздзелах кожны этап розглядаецца окрема.
Фільтраўванне дакументаў за дапамой $match
$match прымае той самы тип фільтра, які вы бы перадалі функцыі find(). У гэтым прыкладзе толькі тыя дакументы, чыё status равнае "completed", пераходзяць да наступнага этапу.
{
$match: {
status: "completed"
}
}
Разместіце $match якомога раней. Кожны дакумент, які адмаўляецца на пачатку, значыць на аднаго менш дакумента, якія пазнейшыя этапы должны обрабатваць, а $match у пачатку канвею можа выкарыстоўваць індэксы калекцыі, тады как пазнейшыя этапы працуюць з проміжнымі рэзультатамі, з якімаў індэксы не можу помагаць.
Групаванне і вычысленне сум з дапамой $group
$group скарыгвае дакументы, якія маюць аднаковы ключ, і вырахоўвае значэнні для кожной групы. У прыкладзе за кожнага кліента ствараецца адзін дакумент з сумой замовлення.
{
$group: {
_id: "$customerId",
totalSales: {
$sum: "$amount"
}
}
}
Роботу выканаюць два элементы:
_idвялічынюе ключ групавання; тут ягою ёсць значэнне поляcustomerIdкожнага дакумента (прыметнік$означае "ачыніць гэта поле").$sum— акумулятор, які сумуе значэнняamountдля кожнага дакумента ў групе.
Іншыя акумуляторы працуюць па той жа принцып, уключаючы $avg, $min, $max і $count. Памятайце, што выход $group містыць толькі _id і тыя поля, якія вы вырахавалі; усе іншыя поля аднародных дакумента ўтрачваюцца.
Выбіранне і перакаштовванне палей за дапамою $project
$project выбірае, які поля будуць практычна выходным дадзеннем, і можа стварыць новыя. Якщо значэнне поля задаецца як 1, яно будзе уключана, а _id: 0 явнаўна спрывае ідэнтыфікатор, які пад час стандартной настройкі ўключаецца автаматычна.
{
$project: {
customerId: 1,
totalSales: 1,
_id: 0
}
}
Ён таксама можа вырачваць значэння. Хутчэй $multiply стварае поле totalWithTax, прыкладзяючы к показніку totalSales коефіцыент податку 18%.
{
$project: {
customerId: 1,
totalWithTax: {
$multiply: ["$totalSales", 1.18]
}
}
}
Є адна важлівая деталь, калі гэтыя фрагменты выконваюцца пасля етапа $group: ідэнтыфікатор кліента тады знаходзіцца ў поле _id, а не ў customerId; таму заданне customerId: 1 не дастане нічога. Аб’еднаны пайплайн у канцы рашае гэтыя проблемы, запісваючы customerId: "$_id", чым перайменоўваецца поле. $project трэба спрыяваць як етап, який формуеўкае заканчальны адпаведзь, які вяртае ваш API.
Спаўненне іншага калекцыі за дапамой $lookup
Дакументы часта абсылуецца да дадзейнаў, якія зберагліся ў іншым месцы. У разе калекцыі orders і калекцыі users аператар $lookup запоўнюе поле customer дакладна тымі пользователямі, якія падходзяць да кожнага замовлення.
{
$lookup: {
from: "users",
localField: "customerId",
foreignField: "_id",
as: "customer"
}
}
Для кожнага замовлення MongoDB паруе customerId замовлення з _id у калекцыі users і запісае всі падходжання ў новае масовае поле пад назвай customer. Гэта ўсё, што можна прыравняць да спаўнення ў SQL. Рэзультат завжды будзе масою, нават калі падходзіць толькі аднаму пользователяму, таму часта пасля спаўнення выкарыстоўваецца аператар $unwind або чытаецца першы элемент. Таксама неабходна, каб оба поля мелі аднаковы тип: строка customerId не можа падходзіць да ObjectId у _id.
Сортаванне рэзультатаў за дапамой $sort
$sort аранжуе дакументы па аднай чыстаільнейшай кантэкстны. Значэнне 1 аранжуе у зростаючым порядкам, а -1 — у спадаючым, таму ў прыкладзе кліянты ранжаваны ад найвышэйшага значэння totalSales да найніжэйшага.
{
$sort: {
totalSales: -1
}
}
Аб’еднанне этапаў у адны звястку
Прыгожы рэзультат атрымліваецца, калі этапы з’еднаны ў адну ланцюгавую структуру. Наведзены выкладчык ператварае неапранутыя замовленні на аранжаваны список кліёнтаў і ўсьго выручанага ад яных:
db.orders.aggregate([
{
$match: {
status: "completed"
}
},
{
$group: {
_id: "$customerId",
totalSales: {
$sum: "$amount"
}
}
},
{
$sort: {
totalSales: -1
}
},
{
$project: {
customerId: "$_id",
totalSales: 1,
_id: 0
}
}
]);
Этап за этапам ён:
- Зберагае толькі завершаныя замовленні за дапамогою
$match. - Групавае іх па кліёнтах за дапамогою
$group. - Сумуе сумы замовленняў кожнага кліёнта ў пэрыяд
totalSales. - Аранжуе кліёнтаў па гэтай суме, ад найвышэйшай да найніжэйшай.
- Ўтрымлівае
$project, каб перайменаваць_idуcustomerIdі адмахнуцца_idз рэспансу.
Ёнклюячы імены або адресы электранаў, можна дадаць $lookup па базе users. Размішчанне яго пасля $group і пасля будзь-якага $limit означае, што з’еднанне выконваецца адна раз на кожного кліента, а не адна раз на кожны замовленне.
Галоўныя моманты
Кораткі спосаб прыгадаць основныя этапы:
$match— фільтрацыя.$group— групаванне і вычысленні.$project— выбір і перакаштовка даных.$lookup— з’еднанне колекцыяў.$sort— сортаванне рэзультатаў.
Разам яны пакрываюць большую частку таго, калі потрэбна ў звятынках, панелях керування, тэрміналах аналітыки і бізнес-правілах, калі вы пераходзите за межы базовых функцый CRUD. Порядак мае значэнне: спачатку фільтруйце, пасля — групавайце, з’еднавайце толькі тады, калі даныя цэго дазваляюць, а выхідную форму падбірайце ў канцы. У інтэрв’ю і пад час перагляду дизайна ўмеласць обясніць, чаму той чы іной этап знаходзится там, дзе ён знаходзіцца, є болей пераканальным, чым проста перыявіць, што кожны з іх робіць.
Спаднёе чытанне
- Запобежэнне втраты апдэйтаў у Node.js і MongoDB пад час паралельных збіркі даных — Дазвольце вам дазнацца, як атомныя умовныя апдэйты, оптымістычнае блаканне на адной версii, адпаведныя 409-е рэспансы і транзакцыі не дазволяюць паралельным збіркам даных у MongoDB таямніча адхоўляць даны.