See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]
1 <?php 2 /* 3 * Copyright 2015-present MongoDB, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * https://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 namespace MongoDB\Operation; 19 20 use MongoDB\Driver\Cursor; 21 use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException; 22 use MongoDB\Driver\Server; 23 use MongoDB\Exception\InvalidArgumentException; 24 use MongoDB\Exception\UnexpectedValueException; 25 use MongoDB\Exception\UnsupportedException; 26 27 use function array_intersect_key; 28 use function assert; 29 use function count; 30 use function current; 31 use function is_array; 32 use function is_float; 33 use function is_integer; 34 use function is_object; 35 36 /** 37 * Operation for obtaining an exact count of documents in a collection 38 * 39 * @api 40 * @see \MongoDB\Collection::countDocuments() 41 * @see https://github.com/mongodb/specifications/blob/master/source/crud/crud.rst#countdocuments 42 */ 43 class CountDocuments implements Executable 44 { 45 /** @var string */ 46 private $databaseName; 47 48 /** @var string */ 49 private $collectionName; 50 51 /** @var array|object */ 52 private $filter; 53 54 /** @var array */ 55 private $aggregateOptions; 56 57 /** @var array */ 58 private $countOptions; 59 60 /** @var Aggregate */ 61 private $aggregate; 62 63 /** 64 * Constructs an aggregate command for counting documents 65 * 66 * Supported options: 67 * 68 * * collation (document): Collation specification. 69 * 70 * * comment (mixed): BSON value to attach as a comment to this command. 71 * 72 * Only string values are supported for server versions < 4.4. 73 * 74 * * hint (string|document): The index to use. Specify either the index 75 * name as a string or the index key pattern as a document. If specified, 76 * then the query system will only consider plans using the hinted index. 77 * 78 * * limit (integer): The maximum number of documents to count. 79 * 80 * * maxTimeMS (integer): The maximum amount of time to allow the query to 81 * run. 82 * 83 * * readConcern (MongoDB\Driver\ReadConcern): Read concern. 84 * 85 * * readPreference (MongoDB\Driver\ReadPreference): Read preference. 86 * 87 * * session (MongoDB\Driver\Session): Client session. 88 * 89 * * skip (integer): The number of documents to skip before returning the 90 * documents. 91 * 92 * @param string $databaseName Database name 93 * @param string $collectionName Collection name 94 * @param array|object $filter Query by which to filter documents 95 * @param array $options Command options 96 * @throws InvalidArgumentException for parameter/option parsing errors 97 */ 98 public function __construct(string $databaseName, string $collectionName, $filter, array $options = []) 99 { 100 if (! is_array($filter) && ! is_object($filter)) { 101 throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); 102 } 103 104 if (isset($options['limit']) && ! is_integer($options['limit'])) { 105 throw InvalidArgumentException::invalidType('"limit" option', $options['limit'], 'integer'); 106 } 107 108 if (isset($options['skip']) && ! is_integer($options['skip'])) { 109 throw InvalidArgumentException::invalidType('"skip" option', $options['skip'], 'integer'); 110 } 111 112 $this->databaseName = $databaseName; 113 $this->collectionName = $collectionName; 114 $this->filter = $filter; 115 116 $this->aggregateOptions = array_intersect_key($options, ['collation' => 1, 'comment' => 1, 'hint' => 1, 'maxTimeMS' => 1, 'readConcern' => 1, 'readPreference' => 1, 'session' => 1]); 117 $this->countOptions = array_intersect_key($options, ['limit' => 1, 'skip' => 1]); 118 119 $this->aggregate = $this->createAggregate(); 120 } 121 122 /** 123 * Execute the operation. 124 * 125 * @see Executable::execute() 126 * @return integer 127 * @throws UnexpectedValueException if the command response was malformed 128 * @throws UnsupportedException if collation or read concern is used and unsupported 129 * @throws DriverRuntimeException for other driver errors (e.g. connection errors) 130 */ 131 public function execute(Server $server) 132 { 133 $cursor = $this->aggregate->execute($server); 134 assert($cursor instanceof Cursor); 135 136 $allResults = $cursor->toArray(); 137 138 /* If there are no documents to count, the aggregation pipeline has no items to group, and 139 * hence the result is an empty array (PHPLIB-376) */ 140 if (count($allResults) == 0) { 141 return 0; 142 } 143 144 $result = current($allResults); 145 if (! is_object($result) || ! isset($result->n) || ! (is_integer($result->n) || is_float($result->n))) { 146 throw new UnexpectedValueException('count command did not return a numeric "n" value'); 147 } 148 149 return (integer) $result->n; 150 } 151 152 private function createAggregate(): Aggregate 153 { 154 $pipeline = [ 155 ['$match' => (object) $this->filter], 156 ]; 157 158 if (isset($this->countOptions['skip'])) { 159 $pipeline[] = ['$skip' => $this->countOptions['skip']]; 160 } 161 162 if (isset($this->countOptions['limit'])) { 163 $pipeline[] = ['$limit' => $this->countOptions['limit']]; 164 } 165 166 $pipeline[] = ['$group' => ['_id' => 1, 'n' => ['$sum' => 1]]]; 167 168 return new Aggregate($this->databaseName, $this->collectionName, $pipeline, $this->aggregateOptions); 169 } 170 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body