sql >> Database >  >> NoSQL >> MongoDB

Aggregatie beperken in gegroepeerde aggregatie

Aangezien uw vraag momenteel onduidelijk is, hoop ik echt dat u bedoelt dat u twee Site . wilt specificeren toetsen en 2 Software sleutels, want dat is een leuk en eenvoudig antwoord dat je gewoon kunt toevoegen aan je $match-fase zoals in:

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

En we kunnen allemaal juichen en gelukkig zijn;)

Als uw vraag echter iets duivelser is, zoals het verkrijgen van de top 2 Sites en Software inzendingen van het resultaat op duur, dan danken wij u hartelijk voor het voortbrengen van deze gruwel .

Waarschuwing:

Uw kilometerstand kan variëren van wat u eigenlijk wilt doen of dat dit gaat opblazen door de enorme omvang van uw resultaten. Maar dit volgt als een voorbeeld van wat u te wachten staat:

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}

])  

Wat dat oplevert is *niet precies de schone reeks resultaten die ideaal zou zijn, maar het is iets waarmee programmatisch kan worden gewerkt, en beter dan het filteren van de vorige resultaten in een lus. (Mijn gegevens van testen)

{
    "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
}

Dus je ziet dat je de top 2 Sites krijgt in de array, met de bovenste 2 Software items ingebed in elk. Aggregatie zelf kan dit niet verder ophelderen, omdat we zouden moeten opnieuw samenvoegen de items hebben we apart gesplitst om dit te doen, en tot nu toe is er geen operator die we zouden kunnen gebruiken om deze actie uit te voeren.

Maar dat was leuk. Het is niet alles zoals gedaan, maar de meeste van de weg, en om daar een antwoord van 4 documenten van te maken, zou relatief triviale code zijn. Maar mijn hoofd doet nu al pijn.




  1. C# mongodb - hoe geneste array-elementen bij te werken

  2. Hoe in Mongoose een array te valideren en tegelijkertijd de elementen ervan?

  3. Regex-query's uitvoeren met PyMongo

  4. Hoe MongoDB dynamische attributen bijwerken?