Skip to content

Commit 93d06a4

Browse files
committed
feat(model): add countDocuments()
Fix #6643 Re: mongodb/node-mongodb-native#1774
1 parent cb2a9a8 commit 93d06a4

File tree

4 files changed

+131
-4
lines changed

4 files changed

+131
-4
lines changed

lib/model.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,6 +1688,38 @@ Model.findOne = function findOne(conditions, projection, options, callback) {
16881688
return mq.findOne(conditions, callback);
16891689
};
16901690

1691+
/**
1692+
* Counts number of matching documents in a database collection. This method
1693+
* is deprecated, use `countDocuments()` instead.
1694+
*
1695+
* ####Example:
1696+
*
1697+
* Adventure.count({ type: 'jungle' }, function (err, count) {
1698+
* if (err) ..
1699+
* console.log('there are %d jungle adventures', count);
1700+
* });
1701+
*
1702+
* @deprecated
1703+
* @param {Object} conditions
1704+
* @param {Function} [callback]
1705+
* @return {Query}
1706+
* @api public
1707+
*/
1708+
1709+
Model.countDocuments = function count(conditions, callback) {
1710+
if (typeof conditions === 'function') {
1711+
callback = conditions;
1712+
conditions = {};
1713+
}
1714+
1715+
// get the mongodb collection object
1716+
const mq = new this.Query({}, {}, this, this.collection);
1717+
1718+
callback = this.$wrapCallback(callback);
1719+
1720+
return mq.countDocuments(conditions, callback);
1721+
};
1722+
16911723
/**
16921724
* Counts number of matching documents in a database collection.
16931725
*

lib/query.js

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1748,7 +1748,33 @@ Query.prototype._count = function(callback) {
17481748
};
17491749

17501750
/**
1751-
* Specifying this query as a `count` query.
1751+
* Thunk around countDocuments()
1752+
*
1753+
* @param {Function} [callback]
1754+
* @see countDocuments http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#countDocuments
1755+
* @api private
1756+
*/
1757+
1758+
Query.prototype._countDocuments = function(callback) {
1759+
try {
1760+
this.cast(this.model);
1761+
} catch (err) {
1762+
this.error(err);
1763+
}
1764+
1765+
if (this.error()) {
1766+
return callback(this.error());
1767+
}
1768+
1769+
const conds = this._conditions;
1770+
const options = this._optionsForExec();
1771+
1772+
this._collection.collection.countDocuments(conds, options, utils.tick(callback));
1773+
};
1774+
1775+
/**
1776+
* Specifies this query as a `count` query. This method is deprecated, use
1777+
* `countDocuments()` instead.
17521778
*
17531779
* Passing a `callback` executes the query.
17541780
*
@@ -1769,6 +1795,7 @@ Query.prototype._count = function(callback) {
17691795
* console.log('there are %d kittens', count);
17701796
* })
17711797
*
1798+
* @deprecated
17721799
* @param {Object} [criteria] mongodb selector
17731800
* @param {Function} [callback] optional params are (error, count)
17741801
* @return {Query} this
@@ -1798,6 +1825,58 @@ Query.prototype.count = function(conditions, callback) {
17981825
return this;
17991826
};
18001827

1828+
/**
1829+
* Specifies this query as a `countDocuments()` query. Behaves like `count()`,
1830+
* except for [`$where` and a couple geospatial operators](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#countDocuments).
1831+
*
1832+
* Passing a `callback` executes the query.
1833+
*
1834+
* This function triggers the following middleware.
1835+
*
1836+
* - `countDocuments()`
1837+
*
1838+
* ####Example:
1839+
*
1840+
* const countQuery = model.where({ 'color': 'black' }).countDocuments();
1841+
*
1842+
* query.countDocuments({ color: 'black' }).count(callback);
1843+
*
1844+
* query.countDocuments({ color: 'black' }, callback);
1845+
*
1846+
* query.where('color', 'black').countDocuments(function(err, count) {
1847+
* if (err) return handleError(err);
1848+
* console.log('there are %d kittens', count);
1849+
* });
1850+
*
1851+
* @param {Object} [criteria] mongodb selector
1852+
* @param {Function} [callback] optional params are (error, count)
1853+
* @return {Query} this
1854+
* @see countDocuments http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#countDocuments
1855+
* @api public
1856+
*/
1857+
1858+
Query.prototype.countDocuments = function(conditions, callback) {
1859+
if (typeof conditions === 'function') {
1860+
callback = conditions;
1861+
conditions = undefined;
1862+
}
1863+
1864+
conditions = utils.toObject(conditions);
1865+
1866+
if (mquery.canMerge(conditions)) {
1867+
this.merge(conditions);
1868+
}
1869+
1870+
this.op = 'countDocuments';
1871+
if (!callback) {
1872+
return this;
1873+
}
1874+
1875+
this._countDocuments(callback);
1876+
1877+
return this;
1878+
};
1879+
18011880
/**
18021881
* Declares or executes a distict() operation.
18031882
*

test/model.test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3319,6 +3319,16 @@ describe('Model', function() {
33193319
});
33203320
});
33213321

3322+
it('countDocuments()', function() {
3323+
const BlogPost = db.model('BlogPost' + random(), bpSchema);
3324+
3325+
return BlogPost.create({ title: 'foo' }).
3326+
then(() => BlogPost.count({ title: 'foo' }).exec()).
3327+
then(count => {
3328+
assert.equal(count, 1);
3329+
});
3330+
});
3331+
33223332
it('update()', function(done) {
33233333
var col = 'BlogPost' + random();
33243334
var BlogPost = db.model(col, bpSchema);

test/query.test.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,7 +1129,7 @@ describe('Query', function() {
11291129
assert.ifError(error);
11301130
M.deleteOne({ name: /Stark/ }, function(error) {
11311131
assert.ifError(error);
1132-
M.count({}, function(error, count) {
1132+
M.countDocuments({}, function(error, count) {
11331133
assert.ifError(error);
11341134
assert.equal(count, 1);
11351135
done();
@@ -1250,7 +1250,7 @@ describe('Query', function() {
12501250
Test.remove({ name: /Stark/ }).setOptions({ single: true }).exec(function(error, res) {
12511251
assert.ifError(error);
12521252
assert.equal(res.n, 1);
1253-
Test.count({}, function(error, count) {
1253+
Test.countDocuments({}, function(error, count) {
12541254
assert.ifError(error);
12551255
assert.equal(count, 1);
12561256
done();
@@ -1671,6 +1671,12 @@ describe('Query', function() {
16711671
});
16721672
});
16731673

1674+
it('ignores sort when passed to countDocuments', function() {
1675+
var Product = db.model('Product', 'Product_setOptions_test');
1676+
return Product.create({}).
1677+
then(() => Product.find().sort({_id: 1}).countDocuments({}).exec());
1678+
});
1679+
16741680
it('ignores count when passed to sort', function(done) {
16751681
var Product = db.model('Product', 'Product_setOptions_test');
16761682
Product.find().count({}).sort({_id: 1}).exec(function(error) {
@@ -2698,7 +2704,7 @@ describe('Query', function() {
26982704
Object.assign(query, { price: priceQuery });
26992705

27002706
yield Model.create(tests);
2701-
var count = yield Model.count(query);
2707+
var count = yield Model.countDocuments(query);
27022708
assert.strictEqual(count, 9);
27032709
});
27042710
});

0 commit comments

Comments
 (0)