মঙ্গোডিবি সমষ্টি: মোট রেকর্ড গণনা কীভাবে পাবেন?


105

আমি মংডোব থেকে রেকর্ড আনার জন্য সমষ্টি ব্যবহার করেছি।

$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),
));

আমি যদি এই সন্ধানটি সীমা ছাড়াই সম্পাদন করি তবে 10 টি রেকর্ড আনা হবে। তবে আমি সীমা 2 হিসাবে রাখতে চাই তাই আমি মোট রেকর্ড গণনা পেতে চাই get একত্রিতকরণের সাথে আমি কীভাবে পারি? আমাকে পরামর্শ করুন। ধন্যবাদ


ফলাফলগুলি দেখতে 2 টির মতো দেখতে কেমন হত?
তারযুক্তপ্রেইরি

উত্তর:


104

একক প্রশ্নের মধ্যে একই সাথে পৃষ্ঠাবদ্ধ ফলাফল এবং মোট ফলাফলের সংখ্যা পেতে এটি সবচেয়ে সাধারণভাবে জিজ্ঞাসিত একটি প্রশ্ন। অবশেষে আমি 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 ) ) ) )
))

ফলাফলটি এরকম কিছু দেখবে:

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

8
এটিতে ডকুমেন্টেশন: ডকস.মোংডব . com / v3.2 / references / operator / aggregation / group/ … ... নোট করুন যে এই পদ্ধতির সাথে, সম্পূর্ণ অ-পৃষ্ঠাযুক্ত রেজাল্ট সেটটি অবশ্যই 16 এমবিতে মাপসই করা উচিত।
বিটাউন

8
এটা খাঁটি সোনার! আমি এই কাজটি করার চেষ্টা করছিলাম।
হেনরিক মিরান্ডা

4
ধন্যবাদ ছেলে! আমি ঠিক প্রয়োজন { $group: { _id: null, count: { $sum:1 }, result: { $push: '$$ROOT' }}}( {$group:{}}গণনা মোট অনুসন্ধানের পরে সন্নিবেশ করান ।
লিবারেটর

4
আপনি ফলাফল সেট সীমা কিভাবে প্রয়োগ করবেন? ফলাফলগুলি এখন নেস্টেড অ্যারে
ভ্যালেন

4
আমার জীবন এখন সম্পূর্ণ, আমি খুশি মারা যেতে পারি
জ্যাক

91

যেহেতু v.3.4 (আমার মনে হয়) মঙ্গোডিবিতে এখন ' ফেসট ' নামে একটি নতুন সমষ্টি পাইপলাইন অপারেটর রয়েছে যা তাদের নিজস্ব কথায়:

একই ইনপুট ডকুমেন্টগুলির এক সেট পর্যায়ে একাধিক সংহত পাইপলাইনগুলি প্রক্রিয়া করে। প্রতিটি উপ-পাইপলাইনের আউটপুট নথিতে তার নিজস্ব ক্ষেত্র রয়েছে যেখানে ফলাফলগুলি নথির অ্যারে হিসাবে সংরক্ষণ করা হয়।

এই বিশেষ ক্ষেত্রে, এর অর্থ এই যে কেউ এইরকম কিছু করতে পারে:

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

ফলাফলটি হবে (প্রাক্তন 100 মোট ফলাফলের জন্য):

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

13
এটি দুর্দান্ত কাজ করে, ৩.৪ এর হিসাবে এটি গ্রহণযোগ্য উত্তর হওয়া উচিত
অ্যাডাম রেইস

এত অ্যারেফুল রেজাল্টকে সাধারণ দুটি ফিল্ড অবজেক্টে রূপান্তর করতে আমার আরেকটি দরকার $project?
সার্জ

4
এটি অবশ্যই গ্রহণযোগ্য উত্তর হতে হবে। কবজ মত কাজ।
অরোটিন আঘাজারিয়ান

9
এটি আজ গ্রহণযোগ্য উত্তর হওয়া উচিত। যাইহোক, আমি $ রূপের সাথে পেজিং ব্যবহার করার সময় পারফরম্যান্সের সমস্যাগুলি পেয়েছি। অন্যান্য আপ ভোট দেওয়া উত্তরেও $ স্লাইস সহ কর্মক্ষমতা সংক্রান্ত সমস্যা রয়েছে। পাইপলাইনে ip এড়িয়ে যাওয়া এবং $ সীমা নির্ধারণ করা এবং গণনার জন্য পৃথক কল করা আমার পক্ষে ভাল। আমি মোটামুটি বড় ডেটা সেটগুলির বিপরীতে এটি পরীক্ষা করেছি।
জেপ্পি

59

ফলাফল সংগ্রহের মোট সংখ্যা গণনা করতে এটি ব্যবহার করুন।

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

4
ধন্যবাদ তবে, আমি সংশ্লিষ্ট কোড গণনা (যেমন, গ্রুপ 1 => 2 রেকর্ড, গ্রুপ 3 => 5 রেকর্ড ইত্যাদি) পেতে আমার কোডিংয়ে "ভিউগুলি" ব্যবহার করেছি। আমি রেকর্ড গণনা পেতে (অর্থাৎ মোট: 120 টি রেকর্ড) পেতে চাই। আশা করি আপনি বুঝতে পেরেছেন ..
ব্যবহারকারী 2987836

37

আপনি টু অ্যারে ফাংশনটি ব্যবহার করতে পারেন এবং তারপরে মোট রেকর্ড গণনার জন্য এর দৈর্ঘ্য পেতে পারেন।

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

4
যদিও এটি "যথাযথ" সমাধান হিসাবে কাজ না করে, এটি আমাকে কিছু ডিবাগ করতে সহায়তা করেছিল - এটি 100% সমাধান না হলেও এটি কাজ করে।
জোহান মার্কস

4
এটি আসল সমাধান নয়।
ফুরকান বারাণ

4
TypeError: Parent.aggregate(...).toArray is not a functionএই সমাধানটি দিয়ে আমি এই ত্রুটিটি দিয়েছি।
মোহাম্মদ হোসেইন শোজেইনিয়া

ধন্যবাদ এই আমি খুঁজছিলাম ছিল।
skvp

এটি সমস্ত সম্মিলিত ডেটা আনবে এবং তারপরে সেই অ্যারের দৈর্ঘ্য ফিরিয়ে দেবে। একটি ভাল অনুশীলন না। পরিবর্তে আপনি একত্রিত পাইপলাইনে count $ গণনা: 'গণনা' add যুক্ত করতে পারেন
আসলাম শাইক

21

মোট দস্তাবেজ গণনা পেতে $ গণনা সমষ্টি পাইপলাইন পর্যায়টি ব্যবহার করুন :

প্রশ্ন :

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

ফলাফল:

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

এটি ঠিক মনোমুগ্ধকর মতো কাজ করে, তবে পারফরম্যান্স-ভিত্তিক এটি কি ভাল?
ana.aree

পরিষ্কার সমাধান। ধন্যবাদ
skvp

13

আমি এটি এইভাবে করেছি:

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

সমষ্টিটি অ্যারেটি ফিরিয়ে দেবে তাই কেবল এটি লুপ করুন এবং চূড়ান্ত সূচকটি পান।

এবং এটি করার অন্যান্য উপায় হ'ল:

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

fww আপনার কোন varঘোষণাপত্র বা mapকল প্রয়োজন নেই । আপনার প্রথম উদাহরণের প্রথম 3 লাইন যথেষ্ট।
ম্যাডব্রেকস

7

@ ডাইভারজেন্ট দ্বারা প্রদত্ত সমাধান কাজ করে তবে আমার অভিজ্ঞতায় 2 টি প্রশ্ন থাকা ভাল:

  1. ফিল্টার করার জন্য এবং তারপরে ফিল্টারকারী উপাদানগুলির সংখ্যা পেতে আইডি দ্বারা গ্রুপিং করুন। এখানে ফিল্টার করবেন না, এটি অপ্রয়োজনীয়।
  2. দ্বিতীয় কোয়েরি যা ফিল্টার করে, বাছাই করে এবং প্যাগিনেট করে।

বড় সংগ্রহের জন্য 16MB এর ডকুমেন্ট মেমরির সীমাবদ্ধতায় $$ রুট এবং $ স্লাইস ব্যবহার করে সমাধান olution এছাড়াও, বড় সংগ্রহের জন্য দুটি ক্যোয়ারী একসাথে $$ রুট পুশিংয়ের চেয়ে দ্রুত চলমান বলে মনে হয়। আপনি এগুলিও সমান্তরালভাবে চালাতে পারেন, সুতরাং আপনি কেবল দুটি প্রশ্নের ধীর সীমাবদ্ধ (সম্ভবত এটি যা সাজান)।

আমি 2 টি প্রশ্ন এবং সমষ্টি কাঠামো ব্যবহার করে এই সমাধানটি স্থির করেছি (দ্রষ্টব্য - আমি এই উদাহরণে নোড.জেএস ব্যবহার করি তবে ধারণাটি একই):

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
//const total_count = await User.find(query).countDocuments();
//const users = await User.find(query).skip(+offset).limit(+limit).sort({[sort]: order}).select('-password');
const result = await User.aggregate([
  {$match : query},
  {$sort: {[sort]:order}},
  {$project: {password: 0, avatarData: 0, tokens: 0}},
  {$facet:{
      users: [{ $skip: +offset }, { $limit: +limit}],
      totalCount: [
        {
          $count: 'count'
        }
      ]
    }}
  ]);
console.log(JSON.stringify(result));
console.log(result[0]);
return res.status(200).json({users: result[0].users, total_count: result[0].totalCount[0].count});

4
কোডের উত্তরের সাথে ব্যাখ্যামূলক পাঠ্য অন্তর্ভুক্ত করা সাধারণত ভাল অনুশীলন।

3

এটি একাধিক ম্যাচের শর্তগুলির জন্য কাজ হতে পারে

            const query = [
                {
                    $facet: {
                    cancelled: [
                        { $match: { orderStatus: 'Cancelled' } },
                        { $count: 'cancelled' }
                    ],
                    pending: [
                        { $match: { orderStatus: 'Pending' } },
                        { $count: 'pending' }
                    ],
                    total: [
                        { $match: { isActive: true } },
                        { $count: 'total' }
                    ]
                    }
                },
                {
                    $project: {
                    cancelled: { $arrayElemAt: ['$cancelled.cancelled', 0] },
                    pending: { $arrayElemAt: ['$pending.pending', 0] },
                    total: { $arrayElemAt: ['$total.total', 0] }
                    }
                }
                ]
                Order.aggregate(query, (error, findRes) => {})

2

সমষ্টিটি প্রয়োগের পরে আমার নিখুঁত মোট গণনা দরকার। এটি আমার পক্ষে কাজ করেছে:

db.mycollection.aggregate([
    {
        $group: { 
            _id: { field1: "$field1", field2: "$field2" },
        }
    },
    { 
        $group: { 
            _id: null, count: { $sum: 1 } 
        } 
    }
])

ফলাফল:

{
    "_id" : null,
    "count" : 57.0
}

2

মঙ্গোডিবি সমষ্টি করার সময় মোট রেকর্ড গণনা পাওয়ার কয়েকটি উপায় এখানে রয়েছে:


  • ব্যবহার $count:

    db.collection.aggregate([
       // Other stages here
       { $count: "Total" }
    ])
    

    1000 রেকর্ড পাওয়ার জন্য এটি গড়ে 2 এমএস নেয় এবং এটি দ্রুততম উপায়।


  • ব্যবহার .toArray():

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

    1000 রেকর্ড পাওয়ার জন্য এটি গড়ে 18 এমএস নেয়।


  • ব্যবহার .itcount():

    db.collection.aggregate([...]).itcount()
    

    1000 রেকর্ড পাওয়ার জন্য এটি গড়ে 14 এমএস নেয়।


0

দুঃখিত, তবে আমি মনে করি আপনার দুটি প্রশ্নের প্রয়োজন। মোট দেখার জন্য একটি এবং অন্যটি দলবদ্ধ রেকর্ডের জন্য।

আপনি এই উত্তর দরকারী খুঁজে পেতে পারেন


ধন্যবাদ..আমিও তাই মনে করি..কিন্তু, একীকরণের সাথে কোনও বিকল্প নেই .. :(
ইউজার 2987836

4
আমিও একই ধরণের পরিস্থিতির মুখোমুখি হয়েছি। 2 কোয়েরি করা ছাড়া কোনও উত্তর ছিল না। :( stackoverflow.com/questions/20113731/...
astroanu

0

আপনি যদি গ্রুপ করতে চান না, তবে নিম্নলিখিত পদ্ধতিটি ব্যবহার করুন:

db.collection.aggregate( [ { $match : { score : { $gt : 70, $lte : 90 } } }, { $count: 'count' } ] );


আমি মনে করি যে প্রশ্নটি জিজ্ঞাসা করছে সে বিষয়টির ভিত্তিতে গ্রুপ করতে চায় না।
mjaggard
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.