MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Aggregation in gruppierter Aggregation begrenzen

Da Ihre Frage derzeit unklar ist, hoffe ich wirklich, dass Sie damit meinen, dass Sie zwei Site angeben möchten Schlüssel und 2 Software Schlüssel, denn das ist eine nette und einfache Antwort, die Sie einfach zu Ihrer $match-Phase hinzufügen können, wie in:

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

Und wir können alle jubeln und uns freuen;)

Wenn Ihre Frage jedoch etwas teuflischer ist, wie zum Beispiel, die Top 2 Site zu bekommen und Software Einträge aus dem Ergebnis nach Dauer, dann danken wir Ihnen sehr für das Spawnen dieser Abscheulichkeit .

Warnung:

Ihre Laufleistung kann davon abhängen, was Sie tatsächlich tun möchten oder ob dies durch die schiere Größe Ihrer Ergebnisse in die Luft gesprengt wird. Aber dies folgt als Beispiel dafür, worauf Sie sich einlassen:

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}

])  

Das Ergebnis ist nun *nicht genau die sauberen Ergebnisse, die ideal wären, aber es ist etwas, mit dem programmatisch gearbeitet werden kann, und besser als das Filtern der vorherigen Ergebnisse in einer Schleife. (Meine Daten aus dem Test)

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

Sie sehen also, Sie erhalten die Top 2 Site im Array, mit den Top 2 Software darin eingebettete Elemente. Die Aggregation selbst kann dies nicht weiter aufklären, da wir re-mergen müssten die Elemente, die wir zu diesem Zweck aufteilen, und bis jetzt gibt es keinen Operator, mit dem wir diese Aktion ausführen könnten.

Aber das hat Spaß gemacht. Es ist nicht alles der Weg getan, aber die meisten des Weges, und daraus eine 4-Dokument-Antwort zu machen, wäre relativ trivialer Code. Aber mein Kopf tut schon weh.