@@ -1829,6 +1829,7 @@ var indexInformation = function(self, options, callback) {
18291829 * @param {ClientSession } [options.session] optional session to use for this operation
18301830 * @param {Collection~countCallback } [callback] The command result callback
18311831 * @return {Promise } returns Promise if no callback passed
1832+ * @deprecated use countDocuments or estimatedDocumentCount instead
18321833 */
18331834Collection . prototype . count = function ( query , options , callback ) {
18341835 var args = Array . prototype . slice . call ( arguments , 0 ) ;
@@ -1839,19 +1840,36 @@ Collection.prototype.count = function(query, options, callback) {
18391840 return executeOperation ( this . s . topology , count , [ this , query , options , callback ] ) ;
18401841} ;
18411842
1842- var count = function ( self , query , options , callback ) {
1843- var skip = options . skip ;
1844- var limit = options . limit ;
1845- var hint = options . hint ;
1846- var maxTimeMS = options . maxTimeMS ;
1843+ /**
1844+ * Gets an estimate of the count of documents in a collection using collection metadata.
1845+ * @method
1846+ * @param {object } [options] Optional settings.
1847+ * @param {number } [options.maxTimeMS] The maximum amount of time to allow the operation to run.
1848+ * @param {Collection~countCallback } [callback] The command result callback.
1849+ * @return {Promise } returns Promise if no callback passed.
1850+ */
1851+ Collection . prototype . estimatedDocumentCount = function ( options , callback ) {
1852+ if ( typeof options === 'function' ) ( callback = options ) , ( options = { } ) ;
1853+ options = options || { } ;
18471854
1848- // Final query
1849- var cmd = {
1850- count : self . s . name ,
1855+ options = typeof options . maxTimeMS === 'number' ? options : { } ;
1856+
1857+ return executeOperation ( this . s . topology , count , [ this , null , options , callback ] ) ;
1858+ } ;
1859+
1860+ const count = function ( collection , query , options , callback ) {
1861+ const skip = options . skip ;
1862+ const limit = options . limit ;
1863+ const hint = options . hint ;
1864+ const maxTimeMS = options . maxTimeMS ;
1865+ query = query || { } ;
1866+
1867+ const cmd = {
1868+ count : collection . s . name ,
18511869 query : query
18521870 } ;
18531871
1854- // Add limit, skip and maxTimeMS if defined
1872+ // Add skip, limit, maxTimeMS, and hint if defined
18551873 if ( typeof skip === 'number' ) cmd . skip = skip ;
18561874 if ( typeof limit === 'number' ) cmd . limit = limit ;
18571875 if ( typeof maxTimeMS === 'number' ) cmd . maxTimeMS = maxTimeMS ;
@@ -1860,21 +1878,74 @@ var count = function(self, query, options, callback) {
18601878 options = shallowClone ( options ) ;
18611879
18621880 // Ensure we have the right read preference inheritance
1863- options = getReadPreference ( self , options , self . s . db ) ;
1881+ options = getReadPreference ( collection , options , collection . s . db ) ;
18641882
18651883 // Do we have a readConcern specified
1866- decorateWithReadConcern ( cmd , self , options ) ;
1884+ decorateWithReadConcern ( cmd , collection , options ) ;
18671885
18681886 // Have we specified collation
1869- decorateWithCollation ( cmd , self , options ) ;
1887+ decorateWithCollation ( cmd , collection , options ) ;
18701888
18711889 // Execute command
1872- self . s . db . command ( cmd , options , function ( err , result ) {
1890+ collection . s . db . command ( cmd , options , function ( err , result ) {
18731891 if ( err ) return handleCallback ( callback , err ) ;
18741892 handleCallback ( callback , null , result . n ) ;
18751893 } ) ;
18761894} ;
18771895
1896+ /**
1897+ * Gets the number of documents matching the filter.
1898+ * @param {object } [query] the query for the count
1899+ * @param {object } [options] Optional settings.
1900+ * @param {object } [options.collation] Specifies a collation.
1901+ * @param {string|object } [options.hint] The index to use.
1902+ * @param {number } [options.limit] The maximum number of document to count.
1903+ * @param {number } [options.maxTimeMS] The maximum amount of time to allow the operation to run.
1904+ * @param {number } [options.skip] The number of documents to skip before counting.
1905+ * @param {Collection~countCallback } [callback] The command result callback.
1906+ * @return {Promise } returns Promise if no callback passed.
1907+ */
1908+
1909+ Collection . prototype . countDocuments = function ( query , options , callback ) {
1910+ var args = Array . prototype . slice . call ( arguments , 0 ) ;
1911+ callback = typeof args [ args . length - 1 ] === 'function' ? args . pop ( ) : undefined ;
1912+ query = args . length ? args . shift ( ) || { } : { } ;
1913+ options = args . length ? args . shift ( ) || { } : { } ;
1914+
1915+ return executeOperation ( this . s . topology , countDocuments , [ this , query , options , callback ] ) ;
1916+ } ;
1917+
1918+ const countDocuments = function ( collection , query , options , callback ) {
1919+ const skip = options . skip ;
1920+ const limit = options . limit ;
1921+ options = Object . assign ( { } , options ) ;
1922+
1923+ const pipeline = [ { $match : query } ] ;
1924+
1925+ // Add skip and limit if defined
1926+ if ( typeof skip === 'number' ) {
1927+ pipeline . push ( { $skip : skip } ) ;
1928+ }
1929+
1930+ if ( typeof limit === 'number' ) {
1931+ pipeline . push ( { $limit : limit } ) ;
1932+ }
1933+
1934+ pipeline . push ( { $group : { _id : null , n : { $sum : 1 } } } ) ;
1935+
1936+ delete options . limit ;
1937+ delete options . skip ;
1938+
1939+ // TODO: look out for how this plays into operations refactor
1940+ collection . aggregate ( pipeline , options , function ( err , result ) {
1941+ if ( err ) return handleCallback ( callback , err ) ;
1942+ result
1943+ . toArray ( )
1944+ . then ( docs => handleCallback ( callback , null , docs [ 0 ] . n ) )
1945+ . catch ( e => handleCallback ( e ) ) ;
1946+ } ) ;
1947+ } ;
1948+
18781949/**
18791950 * The distinct command returns returns a list of distinct values for the given key across a collection.
18801951 * @method
0 commit comments