web-dev-qa-db-fra.com

Requête limite/décalage et comptage de mangouste

Un peu étrange sur les performances des requêtes ... Je dois exécuter une requête qui effectue un nombre total de documents et peut également renvoyer un ensemble de résultats pouvant être limité et décalé.

Donc, j'ai 57 documents au total, et l'utilisateur veut 10 documents compensés par 20.

Je peux penser à deux façons de procéder. Il faut d’abord interroger tous les 57 documents (renvoyés sous forme de tableau), puis utiliser array.slice pour renvoyer les documents qu’ils souhaitent. La deuxième option consiste à exécuter 2 requêtes, la première à l'aide de la méthode native "count" de mongo, puis à exécuter une seconde requête à l'aide des agrégateurs natifs $ limit et $ skip de mongo.

Selon vous, quelle serait la meilleure échelle? Faire tout cela en une seule requête ou en exécuter deux différentes?

Modifier:

// 1 query
var limit = 10;
var offset = 20;

Animals.find({}, function (err, animals) {
    if (err) {
        return next(err);
    }

    res.send({count: animals.length, animals: animals.slice(offset, limit + offset)});
});


// 2 queries
Animals.find({}, {limit:10, skip:20} function (err, animals) {            
    if (err) {
        return next(err);
    }

    Animals.count({}, function (err, count) {
        if (err) {
            return next(err);
        }

        res.send({count: count, animals: animals});
    });
});
56
leepowell

Je vous suggère d'utiliser 2 requêtes:

  1. db.collection.count() retournera le nombre total d'éléments. Cette valeur est stockée quelque part dans Mongo et n’est pas calculée.

  2. db.collection.find().skip(20).limit(10) ici, je suppose que vous pouvez utiliser un tri par champ. N'oubliez pas d'ajouter un index sur ce champ. Cette requête sera rapide aussi.

Je pense que vous ne devriez pas interroger tous les éléments et effectuer des sauts et des prélèvements, car plus tard, lorsque vous aurez des données volumineuses, vous aurez des problèmes de transfert et de traitement des données.

90
user854301

Après avoir dû m'occuper moi-même de ce problème, j'aimerais développer la réponse de user854301.

Mongoose ^ 4.13.8 J'ai pu utiliser une fonction appelée toConstructor() qui m'a permis d'éviter de créer la requête plusieurs fois lorsque des filtres sont appliqués. Je sais que cette fonction est également disponible dans les anciennes versions, mais vous devrez vérifier la documentation Mongoose pour le confirmer.

Les utilisations suivantes promettent Bluebird:

let schema = Query.find({ name: 'bloggs', age: { $gt: 30 } });

// save the query as a 'template'
let query = schema.toConstructor();

return Promise.join(
    schema.count().exec(),
    query().limit(limit).skip(skip).exec(),

    function (total, data) {
        return { data: data, total: total }
    }
);

Maintenant, la requête de comptage renvoie le nombre total d'enregistrements correspondant et les données renvoyées constituent un sous-ensemble du nombre total d'enregistrements.

Veuillez noter la requête () around autour () qui construit la requête.

1
oli_taz

Au lieu d'utiliser 2 requêtes, utilisez l'agrégat dans une requête unique

Aggregate "$ facet" peut être récupéré plus rapidement, leTotal Countet leDonnées avec sauts et limites

    db.collection.aggregate([

      //{$sort: {...}}

      //{$match:{...}}

      {$facet:{
        "stage1" : [
           $group:{_id:null, count:{$sum:1}}
         ],

        "stage2" : [
               { "$skip": 0}, {"$limit": 2}
         ]

      }},


     {$unwind: "$stage1"},

      //output projection
     {$project:{
        count: "$stage1.count",
        data: "$stage2"
     }}

 ]);

sortie comme suit: -

[
 count: 50,
 data: [
    {...},
    {...}
  ]
]
0
DhineshYes