web-dev-qa-db-fra.com

Cadre d'agrégation Mongodb | Regrouper sur plusieurs valeurs?

Je voudrais utiliser le cadre d'agrégation de mongoDB pour exécuter ce qui ressemblerait un peu à SQL:

SELECT SUM(A), B, C from myTable GROUP BY B, C;

Les documents indiquent:

Vous pouvez spécifier un seul champ à partir des documents du pipeline, une valeur précédemment calculée ou une clé d'agrégation composée de plusieurs champs entrants.

Mais on ne sait pas vraiment ce qu'est une "clé agrégée composée de plusieurs champs entrants"?

Mon jeu de données est un peu comme ceci:

[{ "timeStamp" : 1341834988666, "label" : "sharon", "responseCode" : "200", "value" : 10, "success" : "true"},
{ "timeStamp" : 1341834988676, "label" : "paul", "responseCode" : "200", "value" : 60, "success" : "true"},
{ "timeStamp" : 1341834988686, "label" : "paul", "responseCode" : "404", "value" : 15, "success" : "true"},
{ "timeStamp" : 1341834988696, "label" : "sharon", "responseCode" : "200", "value" : 35, "success" : "false"},
{ "timeStamp" : 1341834988166, "label" : "paul", "responseCode" : "200", "value" : 40, "success" : "true"},
{ "timeStamp" : 1341834988266, "label" : "paul", "responseCode" : "404", "value" : 99, "success" : "false"}]

Ma requête ressemble à ceci:

resultsCollection.aggregate(
    { $match : { testid : testid} },
    { $skip : alreadyRead },
    { $project : {
            timeStamp : 1 ,
            label : 1,
            responseCode : 1 ,
            value : 1,
            success : 1
        }},
    { $group : {
            _id : "$label",
            max_timeStamp : { $timeStamp : 1 },
            count_responseCode : { $sum : 1 },
            avg_value : { $sum : "$value" },
            count_success : { $sum : 1 }
        }},
    { $group : {
            ?
        }}
);

Mon instinct était d'essayer de diriger les résultats vers un deuxième groupe, je sais que vous pouvez le faire mais cela ne fonctionnera pas car le premier groupe réduit déjà trop le jeu de données et le niveau de détail requis est perdu.

Ce que je veux faire, c'est grouper en utilisant label, responseCode et success et obtenir la somme de la valeur du résultat. Cela devrait ressembler un peu à:

label   | code | success | sum_of_values | count
sharon  | 200  |  true   |      10       |   1
sharon  | 200  |  false  |      35       |   1
paul    | 200  |  true   |      100      |   2
paul    | 404  |  true   |      15       |   1
paul    | 404  |  false  |      99       |   1

Où il y a cinq groupes:

1. { "timeStamp" : 1341834988666, "label" : "sharon", "responseCode" : "200", "value" : 10, "success" : "true"}

2. { "timeStamp" : 1341834988696, "label" : "sharon", "responseCode" : "200", "value" : 35, "success" : "false"}

3. { "timeStamp" : 1341834988676, "label" : "paul", "responseCode" : "200", "value" : 60, "success" : "true"}
   { "timeStamp" : 1341834988166, "label" : "paul", "responseCode" : "200", "value" : 40, "success" : "true"}

4. { "timeStamp" : 1341834988686, "label" : "paul", "responseCode" : "404", "value" : 15, "success" : "true"}

5. { "timeStamp" : 1341834988266, "label" : "paul", "responseCode" : "404", "value" : 99, "success" : "false"}
26
Oliver Lloyd

OK, la solution consiste donc à spécifier une clé d'agrégation pour la valeur _id. Ceci est documenté ici comme:

Vous pouvez spécifier un seul champ à partir des documents du pipeline, une valeur précédemment calculée ou une clé d'agrégation composée de plusieurs champs entrants.

Mais il ne définit pas réellement le format d'une clé agrégée. En lisant la documentation précédente ici J'ai vu que la méthode collection.group précédente pouvait prendre plusieurs champs et que la même structure était utilisée dans le nouveau framework.

Ainsi, pour regrouper plusieurs champs, vous pouvez utiliser _id : { success:'$success', responseCode:'$responseCode', label:'$label'}

Un péché:

resultsCollection.aggregate(
{ $match : { testid : testid} },
{ $skip : alreadyRead },
{ $project : {
        timeStamp : 1 ,
        label : 1,
        responseCode : 1 ,
        value : 1,
        success : 1
    }},
{ $group : {
        _id :  { success:'$success', responseCode:'$responseCode', label:'$label'},
        max_timeStamp : { $timeStamp : 1 },
        count_responseCode : { $sum : 1 },
        avg_value : { $sum : "$value" },
        count_success : { $sum : 1 }
    }}
);
37
Oliver Lloyd