MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Limiter l'agrégation dans l'agrégation groupée

Comme votre question n'est pas claire actuellement, j'espère vraiment que vous voulez dire que vous voulez spécifier deux Site clés et 2 Software keys parce que c'est une réponse simple et agréable que vous pouvez simplement ajouter à votre phase $match comme dans :

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

Et nous pouvons tous nous réjouir et être heureux ;)

Si toutefois votre question est quelque chose de plus diabolique, comme obtenir les 2 meilleurs Sites et Software entrées du résultat par durée, alors nous vous remercions beaucoup d'avoir engendré cette abomination .

Avertissement :

Votre kilométrage peut varier en fonction de ce que vous voulez réellement faire ou si cela va exploser en raison de la taille de vos résultats. Mais ceci est un exemple de ce qui vous attend :

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}

])  

Maintenant, ce que cela donne n'est *pas exactement l'ensemble propre de résultats qui serait idéal, mais c'est quelque chose qui peut être travaillé par programmation, et mieux que de filtrer les résultats précédents dans une boucle. (Mes données issues des tests)

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

Vous voyez donc que vous obtenez les 2 meilleurs Sites dans le tableau, avec les 2 premiers Software éléments intégrés dans chacun. L'agrégation elle-même ne peut pas clarifier cela davantage, car nous aurions besoin de re-fusionner les éléments que nous avons séparés pour ce faire, et pour l'instant il n'y a aucun opérateur que nous pourrions utiliser pour effectuer cette action.

Mais c'était amusant. Ce n'est pas tout le chemin parcouru, mais la plupart du chemin, et en faire une réponse de 4 documents serait un code relativement trivial. Mais j'ai déjà mal à la tête.