Soru MongoDB Aggregation: Toplam kayıt sayısı nasıl alınır?


Kayıtları mongodb'den almak için bir araya geldim.

$result = $collection->aggregate(array(
  array('$match' => $document),
  array('$group' => array('_id' => '$book_id', 'date' => array('$max' => '$book_viewed'),  'views' => array('$sum' => 1))),
  array('$sort' => $sort),
  array('$skip' => $skip),
  array('$limit' => $limit),
));

Bu sorguyu sınırsız olarak yürütürsem, 10 kayıt alınacaktır. Ama sınırı 2 olarak tutmak istiyorum. Bu yüzden toplam kayıt sayısını almak istiyorum. Toplama ile nasıl yapabilirim? Lütfen bana akıl verin. Teşekkürler


44
2017-12-03 10:06


Menşei


Sadece 2 tane olsaydı sonuç nasıl olurdu? - WiredPrairie


Cevaplar:


Bu, paginated sonucu ve tek bir sorguda eşzamanlı olarak toplam sonuç sayısını elde etmek için en sık sorulan sorulardan biridir. Nihayet başardığımda nasıl hissettiğimi anlatamam LOL.

$result = $collection->aggregate(array(
  array('$match' => $document),
  array('$group' => array('_id' => '$book_id', 'date' => array('$max' => '$book_viewed'),  'views' => array('$sum' => 1))),
  array('$sort' => $sort),

// get total, AND preserve the results
  array('$group' => array('_id' => null, 'total' => array( '$sum' => 1 ), 'results' => array( '$push' => '$$ROOT' ) ),
// apply limit and offset
  array('$project' => array( 'total' => 1, 'results' => array( '$slice' => array( '$results', $skip, $length ) ) ) )
))

Sonuç böyle bir şeye benzeyecek:

[
  {
    "_id": null,
    "total": ...,
    "results": [
      {...},
      {...},
      {...},
    ]
  }
]

64
2017-09-30 06:15



Bu konuda belgeler: docs.mongodb.com/v3.2/reference/operator/aggregation/group/... ... bu yaklaşımla, tüm pürüzlü olmayan sonuç kümelerinin 16 MB'ye sığması gerektiğini unutmayın. - btown
Bu saf altın! Bu işi yapmaya çalışırken cehenneme gidecektim. - Henrique Miranda
Sağol, Henrique Miranda. - Anurag pareek
Teşekkürler adamım! İhtiyacım var { $group: { _id: null, count: { $sum:1 }, result: { $push: '$$ROOT' }}} (sonra ekle {$group:{}} toplam bulmak için. - Liberateur
Sonuç kümesine sınırı nasıl uygularsınız? Sonuçlar şimdi bir yuvalanmış dizi - valen


Koleksiyondaki toplam sayıyı bulmak için bunu kullanın.

db.collection.aggregate( [
{ $match : { score : { $gt : 70, $lte : 90 } } },
{ $group: { _id: null, count: { $sum: 1 } } }
] );

34
2017-12-03 10:19



Teşekkürler. Ancak, ilgili grup sayımını (yani grup 1 => 2 kayıt, grup 3 => 5 kayıt vb.) Almak için kodlarımda "görünümler" kullandım. Kayıtların sayısını almak istiyorum (yani toplam: 120 kayıt). Umarım anlaşmışsındır .. - user2987836


ToArray işlevini kullanabilir ve ardından toplam kayıt sayısı için uzunluğunu alabilirsiniz.

db.CollectionName.aggregate([....]).toArray().length

12
2018-04-25 06:31



benim için çalıştı. Teşekkürler. - Shashank
Perfomances için önerilmez ... büyük db varsa. - Liberateur
Bu "uygun" bir çözüm olarak işe yaramazken, bir şeyleri ayıklamamda bana yardımcı oldu -% 100 bir çözüm olmasa bile işe yarıyor. - Johann Marx
Bu büyük veri için çalışmıyor - Mustafa Mohammadi


Ben bu şekilde yaptım:

db.collection.aggregate([
     { $match : { score : { $gt : 70, $lte : 90 } } },
     { $group: { _id: null, count: { $sum: 1 } } }
] ).map(function(record, index){
        print(index);
 });

Toplama diziyi döndürecek, böylece sadece döngü yapıp son endeksini alacaktır.

Ve bunu yapmanın başka bir yolu:

var count = 0 ;
db.collection.aggregate([
{ $match : { score : { $gt : 70, $lte : 90 } } },
{ $group: { _id: null, count: { $sum: 1 } } }
] ).map(function(record, index){
        count++
 }); 
print(count);

8
2018-06-27 05:34



fwiw gerekmez var beyan veya ne map aramak. İlk örneğinizin ilk 3 satırı yeterlidir. - Madbreaks


V.3.4'ten (bence) beri MongoDB şu anda yeni bir agregasyon boru hattı operatörü var 'faseta'kendi sözleriyle:

Birden çok toplama boru hattını aynı girdi belgeleri kümesinde tek bir aşamada işler. Her bir alt-boru hattının, çıktı belgelerinde, sonuçlarının bir dizi belge olarak saklandığı kendi alanı vardır.

Bu özel durumda, bunun anlamı şu gibi bir şey yapılabilir:

$result = $collection->aggregate([
  { ...execute queries, group, sort... },
  { ...execute queries, group, sort... },
  { ...execute queries, group, sort... },
  $facet: {
    paginatedResults: [{ $skip: skipPage }, { $limit: perPage }],
    totalCount: [
      {
        $count: 'count'
      }
    ]
  }
]);

Sonuç (toplam 100 sonuçla birlikte) olacaktır:

[
  {
    "paginatedResults":[{...},{...},{...}, ...],
    "totalCount":[{"count":100}]
  }
]

6
2018-03-26 04:19



Bu harika çalışıyor, 3.4 olarak kabul edilen cevap olmalı - Adam Reis


@Divergent tarafından sağlanan çözüm işe yaramıyor, ancak deneyimlerime göre 2 sorguya sahip olmak daha iyidir:

  1. Önce filtrelemek ve filtrelenmiş öğelerin sayısını almak için kimliğe göre gruplamak. Buraya filtre uygulamayın, gereksizdir.
  2. Filtreleyen, sıralayan ve sıralayan ikinci sorgu.

$$ ROOT'u zorlamak ve $ slice kullanmak ile oluşan çözüm, büyük koleksiyonlar için 16MB'lık belge bellek sınırlamasına dönüşür. Ayrıca, büyük koleksiyonlar için iki sorgu birlikte, $$ ROOT'u iterek daha hızlı çalışır. Onları paralel olarak da çalıştırabilirsiniz, böylece sadece iki sorgunun yavaşlamasıyla sınırlanırsınız (muhtemelen bir çeşit).

2 çözüm ve toplama çerçevesi kullanarak bu çözüme yerleştim (not - bu örnekte node.js'yi kullanıyorum, ancak fikir aynıdır):

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
            });
          }
      });
    }
  });
});

5
2018-02-09 17:42





Üzgünüm, ama bence iki sorguya ihtiyacın var. Bir grup toplamı ve gruplandırılmış kayıtlar için bir tane.

Yararlı bulabilirsiniz bu cevap


0
2017-12-03 12:42



Teşekkürler .. Ben düşünün.Ancak, toplama ile hiçbir seçenek yoktur .. :( - user2987836
benzer bir duruma girdim. Cevap yoktu, ama 2 sorgu yapmak. :( stackoverflow.com/questions/20113731/... - astroanu


Toplam toplama sonucunu elde etmek için $ count operatörünü kullanın

Sorgu :

db.collection.aggregate(
  [
    {
      $match: {
        ...
      }
    },
    {
      $aggregate: {
        ...
      }
    },
    {
      $count: "totalCount"
    }
  ]
)

Sonuç:

{
   "totalCount" : Number of records (some integer value)
}

0
2017-07-17 13:33