MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Ограничаване на агрегирането при групирано агрегиране

Тъй като въпросът ви в момента е неясен, наистина се надявам, че имате предвид, че искате да посочите два Site ключове и 2 Software ключове, защото това е хубав и прост отговор, който можете просто да добавите към вашата фаза $match, както е в:

{$match: {
    group_id: "20ea74df4f7074b33b520000",
    tracked_item_name: {$in: ['Twitter', 'Facebook', 'Word', 'Excel' ] }
}},

И всички можем да се радваме и да бъдем щастливи;)

Ако обаче въпросът ви е нещо по-дяволско, като получаване на първите 2 Site и Software записи от резултата по продължителност, тогава ние ви благодарим много, че породихте тази мерзост .

Предупреждение:

Вашият пробег може да варира в зависимост от това какво всъщност искате да правите или дали това ще се взриви от самия размер на вашите резултати. Но това следва като пример за това, което ви очаква:

db.collection.aggregate([

    // Match items first to reduce the set
    {$match: {group_id: "20ea74df4f7074b33b520000" }},

    // Group on the types and "sum" of duration
    {$group: {
        _id: {
            tracked_item_type: "$tracked_item_type",
            tracked_item_name: "$tracked_item_name"
         },
         duration: {$sum: "$duration"}
    }},

    // Sort by type and duration descending
    {$sort: { "_id.tracked_item_type": 1, duration: -1 }},

    /* The fun part */

    // Re-shape results to "sites" and "software" arrays 
    {$group: { 
        _id: null,
        sites: {$push:
            {$cond: [
                {$eq: ["$_id.tracked_item_type", "Site" ]},
                { _id: "$_id", duration: "$duration" },
                null
            ]}
        },
        software: {$push:
            {$cond: [
                {$eq: ["$_id.tracked_item_type", "Software" ]},
                { _id: "$_id", duration: "$duration" },
                null
            ]}
        }
    }},


    // Remove the null values for "software"
    {$unwind: "$software"},
    {$match: { software: {$ne: null} }},
    {$group: { 
        _id: "$_id",
        software: {$push: "$software"}, 
        sites: {$first: "$sites"} 
    }},

    // Remove the null values for "sites"
    {$unwind: "$sites"},
    {$match: { sites: {$ne: null} }},
    {$group: { 
        _id: "$_id",
        software: {$first: "$software"},
        sites: {$push: "$sites"} 
    }},


    // Project out software and limit to the *top* 2 results
    {$unwind: "$software"},
    {$project: { 
        _id: 0,
        _id: { _id: "$software._id", duration: "$software.duration" },
        sites: "$sites"
    }},
    {$limit : 2},


    // Project sites, grouping multiple software per key, requires a sort
    // then limit the *top* 2 results
    {$unwind: "$sites"},
    {$group: {
        _id: { _id: "$sites._id", duration: "$sites.duration" },
        software: {$push: "$_id" }
    }},
    {$sort: { "_id.duration": -1 }},
    {$limit: 2}

])  

Сега резултатът от това е *не точно изчистеният набор от резултати, който би бил идеален, но е нещо, с което може да се работи програмно и е по-добре от филтрирането на предишните резултати в цикъл. (Моите данни от тестване)

{
    "result" : [
        {
            "_id" : {
                "_id" : {
                    "tracked_item_type" : "Site",
                    "tracked_item_name" : "Digital Blasphemy"
                 },
                 "duration" : 8000
            },
            "software" : [
                {
                    "_id" : {
                        "tracked_item_type" : "Software",
                        "tracked_item_name" : "Word"
                    },
                    "duration" : 9540
                },

                {
                    "_id" : {
                        "tracked_item_type" : "Software",
                        "tracked_item_name" : "Notepad"
                    },
                    "duration" : 4000
                }
            ]
        },
        {
            "_id" : {
                "_id" : {
                    "tracked_item_type" : "Site",
                    "tracked_item_name" : "Facebook"
                 },
                 "duration" : 7920
            },
            "software" : [
                {
                    "_id" : {
                        "tracked_item_type" : "Software",
                         "tracked_item_name" : "Word"
                    },
                    "duration" : 9540
                },
                {
                    "_id" : {
                        "tracked_item_type" : "Software",
                        "tracked_item_name" : "Notepad"
                    },
                    "duration" : 4000
                }
            ]
        }
    ],
    "ok" : 1
}

Така виждате, че получавате първите 2 Sites в масива, с първите 2 Software елементи, вградени във всяка. Самото агрегиране не може да изясни това повече, защото ще трябва да обединим отново елементите, които разделяме, за да направим това, и все още няма оператор, който да използваме за извършване на това действие.

Но това беше забавно. Не е всичко както е направено, ноповечето между другото и превръщането му в отговор на 4 документа би било сравнително тривиален код. Но главата вече ме боли.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Mongoose получава документи, съответстващи на масива

  2. Актуализиране с AddToSet без актуализиране на нулева стойност с MongoDB C#

  3. Как да проверите дали даден индекс е скрит в MongoDB

  4. MongoDB – Колекцията няма уникален индекс на _id

  5. Flask - Лоша заявка Браузърът (или прокси) изпрати заявка, която този сървър не може да разбере