
// 6.2.1 Produkty, kategorie i opinie


// Z rozdziału 5. - wersja 2 - mniejsza ilość kodu.
product  = db.products.findOne({'slug': 'taczka-9092'})
reviews_count = db.reviews.count({'product_id': product['_id']})

// Rozpoczynamy od podsumowania wszystkich produktów.
ratingSummary = db.reviews.aggregate([     
 {$group : { _id:'$product_id',
             count:{$sum:1} }} 
]).next(); 

/* Wynik.

> ratingSummary = db.reviews.aggregate([
...  {$group : { _id:'$product_id',
...              count:{$sum:1} }}
... ]);
{ "_id" : ObjectId("4c4b1476238d3b4dd5003982"), "count" : 2 }
{ "_id" : ObjectId("4c4b1476238d3b4dd5003981"), "count" : 3 }

*/


// Podsumowanie oceny - dla wybranego produktu
// najpierw wyszukujemy produkt.
product  = db.products.findOne({'slug': 'taczka-9092'})

ratingSummary = db.reviews.aggregate([ 
 {$match : { product_id: product['_id']} }, 
 {$group : { _id:'$product_id',
             count:{$sum:1} }} 
]).next(); 

///*  Wyniki.
//
// {
// "_id" : ObjectId("4c4b1476238d3b4dd5003981"),
// "average" : 4.333333333333333
// }
//
// */

// Dodanie średniej opini dla produktu.

ratingSummary  = db.reviews.aggregate([
    {$match : {'product_id': product['_id']}},
    {$group : { _id:'$product_id',
        average:{$avg:'$rating'},
        count: {$sum:1}}}
]).next();

///* Wyniki.
//
// {
// "_id" : ObjectId("4c4b1476238d3b4dd5003981"),
// "average" : 4.333333333333333,
// "count" : 3
// }
//
// TE DANE ZOSTAŁY ZMODYFIKOWANE, ABY PASOWAŁY DO RYSUNKU.
//
// {
// "_id" : ObjectId("4c4b1476238d3b4dd5003981"),
// "average" : 5,
// "count" : 8
// }
//
// */

// Zaczynamy od grupy.

// Poniższy kod został wykonany PRZED przykładem przedstawionym w książce.

// Tak naprawdę sprawdza, czy pierwsze polecenie użyje indeksu, natomiast drugie nie.

db.reviews.ensureIndex( { product_id: 1 } )

countsByRating = db.reviews.aggregate([
    {$match : {'product_id': product['_id']}},
    {$group : { _id:'$rating',
        count:{$sum:1}}}
],{explain:true})

countsByRating = db.reviews.aggregate([
    {$group : { _id:{'product_id': '$product_id', rating:'$rating'},
        count:{$sum:1}}},
    {$match : {'_id.product_id': product['_id']}}
],{explain:true})

// Przykład z książki:  ***DO ZROBIENIA: zmień to w dokumencie w rozdziale 6 na stronie 9.

ratingSummary  = db.reviews.aggregate([
    {$group : { _id:'$product_id',
        average:{$avg:'$rating'},
        count: {$sum:1}}},
    {$match : {'_id': product['_id']}}
]).next();


// Zliczanie opinii według oceny.
countsByRating = db.reviews.aggregate([
    {$match : {'product_id': product['_id']}},
    {$group : { _id:'$rating',
        count:{$sum:1}}}
]).toArray();

///* Wyniki.
//
// [ { "_id" : 5, "count" : 1 }, { "_id" : 4, "count" : 2 } ]
//
// TE DANE ZOSTAŁY ZMODYFIKOWANE, ABY PASOWAŁY DO RYSUNKU.
//
// [ { "_id" : 5, "count" : 5 },
// { "_id" : 4, "count" : 2 },
// { "_id" : 3, "count" : 1 } ]
//
//
// */

///* Przykład SQL nie został przetestowany.
//
// SELECT RATING, COUNT(*) AS COUNT
// FROM REVIEWS
// WHERE PRODUCT_ID = '4c4b1476238d3b4dd5003981'
// GROUP BY RATING
//
//
// */


// Złączanie kolekcji.
db.products.aggregate([
    {$group : { _id:'$main_cat_id',
        count:{$sum:1}}}
]);

///* Oczekiwane wyniki
//
// { "_id" : ObjectId("6a5b1476238d3b4dd5000048"), "count" : 2 }
//
// */

// Usunięcie istniejących dokumentów z kolekcji mainCategorySummary
db.mainCategorySummary.remove({});

db.products.aggregate([
        {$group : { _id:'$main_cat_id',
            count:{$sum:1}}}
    ]).forEach(function(doc){
        var category = db.categories.findOne({_id:doc._id});
        if (category !== null) {
            doc.category_name = category.name;
        }
        else {
            doc.category_name = 'not found';
        }
        db.mainCategorySummary.insert(doc);
    })

// findOne w mainCategorySummary.

db.mainCategorySummary.findOne()

///*  Oczekiwane wyniki.
//
// {
// "_id" : ObjectId("6a5b1476238d3b4dd5000048"),
// "count" : 2,
// "category_name" : "Narzędzia ogrodowe"
// }
//
// */

// Szybsze złączenia - $unwind

// SZYBSZE ZŁĄCZENIA - $UNWIND
db.products.aggregate([
    {$project : {category_ids:1}},
    {$unwind : '$category_ids'},
    {$group : { _id:'$category_ids',
        count:{$sum:1}}},
    {$out : 'countsByCategory'}
]);

//  Powiązane wywołanie findOne() - użycie $out do utworzenia nowych kolekcji.
db.countsByCategory.findOne()

// Oczekiwane wyniki
// > db.countsByCategory.findOne()
// { "_id" : ObjectId("6a5b1476238d3b4dd5000049"), "count" : 2 }

// 

// Sekcja dotycząca $out i $project.

db.products.aggregate([
    {$group : { _id:'$main_cat_id',
                count:{$sum:1}}}, 
    {$out : 'mainCategorySummary'}
]);


db.products.aggregate([
    {$project : {category_ids:1}}
]);

/* Oczekiwane dane wyjściowe.

> db.products.aggregate([
... {$project : {category_ids:1}}
... ]);
{ "_id" : ObjectId("4c4b1476238d3b4dd5003981"), 
  "category_ids" : [ ObjectId("6a5b1476238d3b4dd5000048"), 
                     ObjectId("6a5b1476238d3b4dd5000049") ] }
{ "_id" : ObjectId("4c4b1476238d3b4dd5003982"), 
  "category_ids" : [ ObjectId("6a5b1476238d3b4dd5000048"), 
                     ObjectId("6a5b1476238d3b4dd5000049") ] }

*/
// 6.2.2 Użytkownik i zamówienie
db.reviews.aggregate([
    {$group :
    {_id : '$user_id',
        count : {$sum : 1},
        avg_helpful : {$avg : '$helpful_votes'}}
    }
])

///* Oczekiwany wynik.
//
// { "_id" : ObjectId("4c4b1476238d3b4dd5000003"),
// "count" : 1, "avg_helpful" : 10 }
// { "_id" : ObjectId("4c4b1476238d3b4dd5000002"),
// "count" : 2, "avg_helpful" : 4 }
// { "_id" : ObjectId("4c4b1476238d3b4dd5000001"),
// "count" : 2, "avg_helpful" : 5 }
//
// */

// Podsumowanie sprzedaży według roku i miesiąca.
db.orders.aggregate([
    {"$match": {"purchase_data":
    {"$gte" : new Date(2010, 0, 1)}}},
    {"$group": {
        "_id": {"year" : {"$year" :"$purchase_data"},
            "month" : {"$month" : "$purchase_data"}},
        "count": {"$sum":1},
        "total": {"$sum":"$sub_total"}}},
    {"$sort": {"_id":-1}}
]);

//    /* Oczekiwane wyniki
//
//     { "_id" : { "year" : 2014, "month" : 11 }, "count" : 1, "total" : 4897 }
//     { "_id" : { "year" : 2014, "month" : 8 }, "count" : 2, "total" : 11093 }
//     { "_id" : { "year" : 2014, "month" : 4 }, "count" : 1, "total" : 4897 }
//
//     */

// Wyszukanie najlepszych klientów na Manhattanie.
upperManhattanOrders = {'shipping_address.zip': {$gte: 10019, $lt: 10040}};

sumByUserId = {_id: '$user_id',
    total: {$sum:'$sub_total'}};

orderTotalLarge = {total: {$gt:10000}};

sortTotalDesc = {total: -1};

db.orders.aggregate([
    {$match: upperManhattanOrders},
    {$group: sumByUserId},
    {$match: orderTotalLarge},
    {$sort: sortTotalDesc}
]);

db.orders.aggregate([
    {$group: sumByUserId},
    {$match: orderTotalLarge},
    {$limit: 10}
]);

//    /* Wyniki.
//
//     { "_id" : ObjectId("4c4b1476238d3b4dd5000002"), "total" : 19588 }
//
//     */

// Przykład łatwiejszy do modyfikacji, dodaliśmy count.
sumByUserId = {_id: '$user_id',
    total: {$sum:'$sub_total'},
    count: {$sum: 1}};

// Ponowne wykonanie zapytania.
db.orders.aggregate([
    {$group: sumByUserId},
    {$match: orderTotalLarge},
    {$limit: 10}
]);

//    /* Wyniki.
//     { "_id" : ObjectId("4c4b1476238d3b4dd5000002"),
//     "total" : 19588, "count" : 4 }
//
//     */

db.orders.aggregate([
    {$match: upperManhattanOrders},
    {$group: sumByUserId},
    {$match: orderTotalLarge},
    {$sort: sortTotalDesc},
    {$out: 'targetedCustomers'}
]);

// Poprawione: dodanie zamówienia wraz z adresem wysyłkowym dla górnego Mmanhattanu.
upperManhattanOrders = {'shipping_address.zip': {$gte: 10019, $lt: 11216}};

db.orders.aggregate([
    {$match: upperManhattanOrders},
    {$group: sumByUserId},
    {$match: orderTotalLarge},
    {$sort: sortTotalDesc},
    {$out: 'targetedCustomers'}
]);

db.targetedCustomers.findOne();

//    /* Oczekiwane wyniki:
//
//     > db.targetedCustomers.findOne();
//     { "_id" : ObjectId("4c4b1476238d3b4dd5000002"), "total" : 19588 }
//
//
//     */