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

Comment agréger avec group by et trier correctement

Il y a quelques pièges ici à comprendre.

Lorsque vous utilisez $group les limites seront triées dans l'ordre dans lequel elles ont été découvertes sans étape initiale ni finale $sort opération. Donc, si vos documents étaient à l'origine dans un ordre comme celui-ci :

{ uid: 1, created: ISODate("2014-05-02..."), another_col : "x" },
{ uid: 1, created: ISODate("2014-05-05..."), another_col : "y" },
{ uid: 3, created: ISODate("2014-05-05..."), another_col : "w" },
{ uid: 2, created: ISODate("2014-05-10..."), another_col : "z" },

Ensuite, utilisez simplement $group sans $sort à la fin du pipeline vous renverrait des résultats comme celui-ci :

{ uid: 1, created: ISODate("2014-05-05..."), another_col : "y" },
{ uid: 3, created: ISODate("2014-05-05..."), another_col : "w" },
{ uid: 2, created: ISODate("2014-05-10..."), another_col : "z" },

C'est un concept, mais il semble en fait que ce que vous attendez dans les résultats nécessite de renvoyer les "derniers autres champs" par un ordre trié de uid est ce que vous recherchez. Dans ce cas, le moyen d'obtenir votre résultat est en fait de $sort d'abord, puis utilisez le $last opérateur :

db.mycollection.aggregate([

    // Sorts everything first by _id and created
    { "$sort": { "_id": 1, "created": 1 } },

    // Group with the $last results from each boundary
    { "$group": {
        "_id": "$uid",
        "created": { "$last": "$created" },
        "another_col": { "$last": "$created" }
    }}
])

Ou appliquez essentiellement le tri à ce que vous voulez.

La différence entre $last et $max est que ce dernier choisira la valeur "la plus élevée" pour le champ donné au sein du regroupement _id , quel que soit l'ordre actuel trié dans l'ordre non trié. D'autre part, $last choisira la valeur qui apparaît dans la même "ligne" que le "dernier" groupement _id valeur.

Si vous cherchiez réellement à trier les valeurs d'un tableau, l'approche est similaire. En gardant les membres du tableau dans l'ordre "créé", vous triez également en premier :

db.mycollection.aggregate([

    // Sorts everything first by _id and created
    { "$sort": { "_id": 1, "created": 1 } },

    // Group with the $last results from each boundary
    { "$group": {
        "_id": "$uid",
        "row": {
            "$push": {
                "created": "$created",
                "another_col": "$another_col"
            }
        }
    }}
])

Et les documents avec ces champs seront ajoutés au tableau avec l'ordre dans lequel ils ont déjà été triés.