Upotreba mongodb aggregation pipeline-a

Share

Do nedavno, relacione baze podataka su bile jedini izbor, međutim, u proteklih nekoliko godina nosql baze postaju sve češće korišćene.

Često inercijom biramo poznate tehnologije, ali to nije uvek dobar izbor. Kada planiramo neki novi projekat, poželjno je pretpostaviti kako će teći razvoj istog, kao i njegova upotreba, koje su specifičnosti koje su nam važne.

U ovom članku ću govoriti o mongodb – nosql bazi podataka koja nije relaciona, koja skladišti json ( u stvari bson – binarne json ) dokumente, konkretnije o njenom „aggregation pipeline“-u.

Koje su prednosti mongodb i kada ima smisla da se odabere za neki projekat?

Treba vam velika brzina upisa: mongodb sa osnovnim podešavanjima ( takozvani „fire and forget“ mod upisa) daje prednost brzini u odnosu na pouzdanost transakcija, pa ako podaci nisu od kritične važnosti i možemo da dozvolimo da se neki zanemarljiv procenat njih izgubi, tu je mongo pravi izbor. Ako i želimo da budemo sigurni u upis u mongo bazu, može se proslediti opcija : safe=true i time na uštrb brzine upisa dobiti siurnost da je svaki podatak upisan.

Mongodb je prirodno distribuiran, pa je pogodan za horizontalno skaliranje, pa ako očekujemo rad sa velikom količinom podataka on može biti dobar izbor.

Dodavanje nove kolone u kolekciju ( pandan tabeli u relacionim bazama ) je trivijalan, samo se doda polje u json fajl i on se snimi u mongo kolekciju, dok ostali podaci u istoj mogu biti bez tog polja.

Ovde treba biti oprezan u pisanju query-a pošto dokumenti različitog formata u istoj kolekciji mogu doneti neke probleme.

Query u mongu se pišu u javascriptu, logika je drugačija, a pisanje zahtevnijih query’a nam umnogome olakšava „aggregation pipeline“.

On se sastoji od 10 tipova transformacija koji se nadovezuju jedna na drugu ( po tome pipeline, kao „pajpovanje“ u unix terminalu).

To su:

  •     $geoNear
  •     $match
  •     $project
  •     $redact
  •     $unwind
  •     $group
  •     $limit
  •     $skip
  •     $sort
  •     $out

Da ne bismo previše raširili temu objašnjavanjem šta koji od njih radi, evo linka ka dokumentaciji http://docs.mongodb.org/manual/reference/operator/aggregation/ a ovde ću pokazati nekoliko primera upotrebe.

Prvo napunimo kolekciju nekim podacima :

db.Student.insert ({Student_Name:"Kalki",  Class: "2", Mark_Scored:100, Subject: ["Tamil", "English", "Maths"]})

db.Student.insert ({Student_Name:"Matsya", Class: "1", Mark_Scored:10,  Subject: ["Tamil", "English"]})


db.Student.insert ({Student_Name:"Krishna",Class: "1", Mark_Scored:50,  Subject: ["Tamil"]})

db.Student.insert ({Student_Name:"Buddha", Class: "2", Mark_Scored:60,  Subject: ["Tamil"]})

db.Student.insert ({Student_Name:"Rama",   Class: "2", Mark_Scored:80,  Subject: ["Tamil"]})


db.Student.insert ({Student_Name:"Krishna",Class: "1", Mark_Scored:50,  Subject: ["English"]})

db.Student.insert ({Student_Name:"Buddha", Class: "2", Mark_Scored:60,  Subject: ["English"]})

db.Student.insert ({Student_Name:"Rama",   Class: "2", Mark_Scored:80,  Subject: ["English"]})


db.Student.insert ({Student_Name:"Matsya", Class: "1", Mark_Scored:67,  Subject: ["Maths"]})

db.Student.insert ({Student_Name:"Krishna",Class: "1", Mark_Scored:95,  Subject: ["Maths"]})

db.Student.insert ({Student_Name:"Buddha", Class: "2", Mark_Scored:88,  Subject: ["Maths"]})

db.Student.insert ({Student_Name:"Rama",   Class: "2", Mark_Scored:40,  Subject: ["Maths"]})

Kolekcija Student se automatski kreira upisom prvog dokumenta u nju, i koristi _id polje kao indeks podrazumevano.

1) Želimo da dohvatimo sve studente koji su pohađali Class 2 i koji imaju preko 80 poena na testu

db.Student.aggregate ([

  {

     "$match":

     {

        "Class":"2",

     }

  },

  {

     "$match":

     {

        "Mark_Scored":

        {

           "$gte": 80

        }

     }

  }

  ])


daje reaultat:


{

            "result" : [

                        {

                                    "_id" : ObjectId("554a5921c1be050f65fbae96"),

                                    "Student_Name" : "Kalki",

                                    "Class" : "2",

                                    "Mark_Scored" : 100,

                                    "Subject" : [

                                                "Tamil",

                                                "English",

                                                "Maths"

                                    ]

                        },

                        {

                                    "_id" : ObjectId("554a5921c1be050f65fbae9a"),

                                    "Student_Name" : "Rama",

                                    "Class" : "2",

                                    "Mark_Scored" : 80,

                                    "Subject" : [

                                                "Tamil"

                                    ]

                        },

                        {

                                    "_id" : ObjectId("554a5921c1be050f65fbae9d"),

                                    "Student_Name" : "Rama",

                                    "Class" : "2",

                                    "Mark_Scored" : 80,

                                    "Subject" : [

                                                "English"

                                    ]

                        },

                        {

                                    "_id" : ObjectId("554a5921c1be050f65fbaea0"),

                                    "Student_Name" : "Buddha",

                                    "Class" : "2",

                                    "Mark_Scored" : 88,

                                    "Subject" : [

                                                "Maths"

                                    ]

                        }

            ],

            "ok" : 1

}

2) Kada su podaci sačuvani u obliku niza, treba nam $unwind:

db.Student.aggregate ([

   {

      "$match":

      {

         "Student_Name": "Kalki",

      }

   },

   {

      "$unwind": "$Subject"

   }

])


daje :


{

            "result" : [

                        {

                                    "_id" : ObjectId("554a5921c1be050f65fbae96"),

                                    "Student_Name" : "Kalki",

                                    "Class" : "2",

                                    "Mark_Scored" : 100,

                                    "Subject" : "Tamil"

                        },

                        {

                                    "_id" : ObjectId("554a5921c1be050f65fbae96"),

                                    "Student_Name" : "Kalki",

                                    "Class" : "2",

                                    "Mark_Scored" : 100,

                                    "Subject" : "English"

                        },

                        {

                                    "_id" : ObjectId("554a5921c1be050f65fbae96"),

                                    "Student_Name" : "Kalki",

                                    "Class" : "2",

                                    "Mark_Scored" : 100,

                                    "Subject" : "Maths"

                        }

            ],

            "ok" : 1

}

– ovde vidimo da smo dobili pojedinačne dokumente za svaki element niza na kom je primenjeno $unwind ( odmotavanje u bukvalnom prevodu ).

3) Ovo je primer agregatne funkcije:

– prosečne ocene studenata na klasi 2

db.Student.aggregate ([

   {

      "$match":

      {

         "Class": "2"

      }

   },

   {

      "$unwind": "$Subject"

   },

   {

      "$group":

      {

         "_id":

         {

            "Student_Name" : "$Student_Name"

         },

         "Avg_Marks":

         {

            "$avg": "$Mark_Scored"

         }

      }

   }

])

dobijamo rezultat:

{

            "result" : [

                        {

                                    "_id" : {

                                                "Student_Name" : "Rama"

                                    },

                                    "Avg_Marks" : 66.66666666666667

                        },

                        {

                                    "_id" : {

                                                "Student_Name" : "Buddha"

                                    },

                                    "Avg_Marks" : 69.33333333333333

                        },

                        {

                                    "_id" : {

                                                "Student_Name" : "Kalki"

                                    },

                                    "Avg_Marks" : 100

                        }

            ],

            "ok" : 1

}

a ako želimo da dobijemo sređenije izlazne podatke, na kraju dodamo $project komandu koja projektuje ono što nam treba u novi pajp u uređenijem obliku

db.Student.aggregate ([

   {

      "$match":

      {

         "Class": "2"

      }

   },

   {

      "$unwind": "$Subject"

   },

   {

      "$group":

      {

         "_id":

         {

            "Student_Name" : "$Student_Name"

         },

         "Avg_Marks":

         {

            "$avg": "$Mark_Scored"

         }

      }

   },

   {

      "$project":

      {

         "_id":0,

         "Name":  "$_id.Student_Name",

         "Average": "$Avg_Marks"

      }

   }

])

dobijamo rezultat

{

            "result" : [

                        {

                                    "Name" : "Rama",

                                    "Average" : 66.66666666666667

                        },

                        {

                                    "Name" : "Buddha",

                                    "Average" : 69.33333333333333

                        },

                        {

                                    "Name" : "Kalki",

                                    "Average" : 100

                        }

            ],

            "ok" : 1

}

i ako želimo da ih sortiramo na kraju dodamo $sort pajp, gde 1 znači asc a -1 znači desc

db.Student.aggregate ([

   {

      "$match":

      {

         "Class": "2"

      }

   },

   {

      "$unwind": "$Subject"

   },

   {

      "$group":

      {

         "_id":

         {

            "Student_Name" : "$Student_Name"

         },

         "Avg_Marks":

         {

            "$avg": "$Mark_Scored"

         }

      }

   },

   {

      "$project":

      {

         "_id":0,

         "Name":  "$_id.Student_Name",

         "Average": "$Avg_Marks"

      }

   },

   {

      "$sort":

      {

         "Average": -1

      }

   }

])

i dobijamo rezultat:

{

            "result" : [

                        {

                                    "Name" : "Kalki",

                                    "Average" : 100

                        },

                        {

                                    "Name" : "Buddha",

                                    "Average" : 69.33333333333333

                        },

                        {

                                    "Name" : "Rama",

                                    "Average" : 66.66666666666667

                        }

            ],

            "ok" : 1

}

Nadam se da će vam biti zanimljivo da se poigrate sa ovim i da možda mongo odaberete kao bazu za neki projekat.

Srećno pajpovanje!

Share

Prijavi se da prvi dobijaš nove blogove i vesti.

Ostavite odgovor

Miodrag Opačić

Senior Back-end developer @Cosmic Development
mm

Miodrag Opačić ima 10 godina radnog iskustva i poseduje zavidno znanje u različitim oblastima informacionih tehnologija. U kompaniji Cosmic Development radi godinu dana na poziciji Senior Back-end developer. U slobodno vreme sprema razne kulinarske specijalitete i uživa u slušanju ploča. 
 

Prijavi se da prvi dobijaš nove blogove i vesti.

Kategorije