sql >> Databasteknik >  >> NoSQL >> MongoDB

Begränsa aggregering i grupperad aggregering

Eftersom din fråga för närvarande är otydlig hoppas jag verkligen att du menar att du vill ange två Site nycklar och 2 Software nycklar eftersom det är ett trevligt och enkelt svar som du bara kan lägga till i din $matchfas som i:

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

Och vi kan alla heja och vara glada;)

Om din fråga däremot är något mer djävulsk, som att få de 2 bästa Sites och Software poster från resultatet efter varaktighet, då tackar vi dig så mycket för att du skapade denna styggel .

Varning:

Din körsträcka kan variera beroende på vad du faktiskt vill göra eller om detta kommer att sprängas av storleken på dina resultat. Men detta följer som ett exempel på vad du är inne på:

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}

])  

Vad det nu resulterar i är *inte exakt den rena uppsättningen resultat som skulle vara idealisk, men det är något som går att arbeta med programmässigt, och bättre än att filtrera de tidigare resultaten i en loop. (Min data från testning)

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

Så du ser att du får de två bästa Sites i arrayen, med de två översta Software objekt inbäddade i varje. Aggregationen i sig kan inte reda ut detta ytterligare, eftersom vi skulle behöva sammanslagna igen objekten vi delar isär för att göra detta, och ännu finns det ingen operatör som vi kan använda för att utföra denna åtgärd.

Men det var kul. Det är inte allt sättet gjort, men de flesta förresten, och att göra det till ett svar på fyra dokument skulle vara relativt trivial kod. Men jag gör redan ont i huvudet.




  1. mongodb server-side javascript är klient-side faktiskt?

  2. 3 sätt att konvertera en sträng till ett datum i MongoDB

  3. Hanterar asynkrona databasfrågor i node.js och mongodb

  4. MongoDB datum och tidsvärde lagras inte korrekt