sql >> Database teknologi >  >> NoSQL >> MongoDB

MongoDB - Aggregation Framework (samlet antal)

Der er en løsning, der bruger push and slice:https://stackoverflow.com/a/39784851/4752635 (@emaniacs nævner det også her).

Men jeg foretrækker at bruge 2 forespørgsler. Løsning med at skubbe $$ROOT og bruge $slice løber ind i dokumenthukommelsesbegrænsning på 16MB for store samlinger. For store samlinger synes to forespørgsler sammen at køre hurtigere end den med $$ROOT-skubber. Du kan også køre dem parallelt, så du er kun begrænset af den langsommere af de to forespørgsler (sandsynligvis den, der sorterer).

  1. Først til filtrering og derefter gruppering efter ID for at få antallet af filtrerede elementer. Filtrer ikke her, det er unødvendigt.
  2. Anden forespørgsel, som filtrerer, sorterer og sideinddeler.

Jeg har afgjort med denne løsning ved hjælp af 2 forespørgsler og aggregeringsramme (bemærk - jeg bruger node.js i dette eksempel):

var aggregation = [
  {
    // If you can match fields at the begining, match as many as early as possible.
    $match: {...}
  },
  {
    // Projection.
    $project: {...}
  },
  {
    // Some things you can match only after projection or grouping, so do it now.
    $match: {...}
  }
];


// Copy filtering elements from the pipeline - this is the same for both counting number of fileter elements and for pagination queries.
var aggregationPaginated = aggregation.slice(0);

// Count filtered elements.
aggregation.push(
  {
    $group: {
      _id: null,
      count: { $sum: 1 }
    }
  }
);

// Sort in pagination query.
aggregationPaginated.push(
  {
    $sort: sorting
  }
);

// Paginate.
aggregationPaginated.push(
  {
    $limit: skip + length
  },
  {
    $skip: skip
  }
);

// I use mongoose.

// Get total count.
model.count(function(errCount, totalCount) {
  // Count filtered.
  model.aggregate(aggregation)
  .allowDiskUse(true)
  .exec(
  function(errFind, documents) {
    if (errFind) {
      // Errors.
      res.status(503);
      return res.json({
        'success': false,
        'response': 'err_counting'
      });
    }
    else {
      // Number of filtered elements.
      var numFiltered = documents[0].count;

      // Filter, sort and pagiante.
      model.request.aggregate(aggregationPaginated)
      .allowDiskUse(true)
      .exec(
        function(errFindP, documentsP) {
          if (errFindP) {
            // Errors.
            res.status(503);
            return res.json({
              'success': false,
              'response': 'err_pagination'
            });
          }
          else {
            return res.json({
              'success': true,
              'recordsTotal': totalCount,
              'recordsFiltered': numFiltered,
              'response': documentsP
            });
          }
      });
    }
  });
});


  1. Hvordan bruger man Redis masseindsættelse?

  2. Brug $stdDevSamp eller $stdDevPop med Spring Mongo

  3. MongoDB-aggregering over et interval

  4. Arkitektur til login-system på MEAN stack?