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

Comment trier des documents en fonction de la longueur d'un champ tableau

Ce que vous semblez vouloir dire ici, c'est que vous voulez "trier" vos résultats en fonction de la "longueur" du tableau "réponses", plutôt qu'une "propriété" appelée "longueur" comme l'implique votre syntaxe. Pour mémoire, cette syntaxe serait impossible ici car votre modèle est "référencé", ce qui signifie que les seules données présentes dans le champ de tableau dans les documents de cette collection sont le ObjectId valeurs de ces documents référencés.

Mais vous pouvez le faire en utilisant .aggregate() méthode et la $size opérateur :

Question.aggregate(
    [
        { "$project": {
            "title": 1,
            "content": 1,
            "created": 1,
            "updated": 1,
            "author": 1,
            "answers": 1,
            "length": { "$size": "$answers" }
        }},
        { "$sort": { "length": -1 } },
        { "$limit": 5 }
    ],
    function(err,results) {
        // results in here
    }
)

Un pipeline d'agrégation fonctionne par étapes. Tout d'abord, il y a un $project pour les champs dans les résultats, où vous utilisez $size pour renvoyer la longueur du tableau spécifié.

Maintenant il y a un champ avec la "longueur", vous suivez les étapes avec $sort et $limit qui sont appliqués comme leurs propres étapes dans un pipeline d'agrégation.

Une meilleure approche serait de toujours conserver la propriété length de votre tableau "réponses" dans le document. Cela facilite le tri et la recherche sans autres opérations. Le maintien de ceci est simple en utilisant le $inc opérateur comme vous $push ou $pull éléments du tableau :

Question.findByIdAndUpdate(id,
    {
        "$push": { "answers": answerId },
        "$inc": { "answerLength": 1 } 
    },
    function(err,doc) {

    }
)

Ou l'inverse lors de la suppression :

Question.findByIdAndUpdate(id,
    {
        "$pull": { "answers": answerId },
        "$inc": { "answerLength": -1 } 
    },
    function(err,doc) {

    }
)

Même si vous n'utilisez pas les opérateurs atomiques, les mêmes principes s'appliquent lorsque vous mettez à jour la "longueur" au fur et à mesure. Ensuite, interroger avec un tri est simple :

Question.find().sort({ "answerLength": -1 }).limit(5).exec(function(err,result) {

});

Comme la propriété est déjà présente dans le document.

Alors faites-le avec .aggregate() sans modifier vos données, ou modifiez vos données pour toujours inclure la longueur en tant que propriété et vos requêtes seront très rapides.