Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -707,10 +707,35 @@ public function delete(string $collection, array $filters = [], int $limit = 1,
*/
public function count(string $collection, array $filters, array $options): int
{
$result = $this->find($collection, $filters, $options);
$list = $result->cursor->firstBatch;
$filters = $this->cleanFilters($filters);

// Use MongoDB's native count command with the working format instad of running find and count the results
$command = [
self::COMMAND_COUNT => $collection,
'query' => $this->toObject($filters),
];

return \count($list);
// Add limit if specified
if (isset($options['limit'])) {
$command['limit'] = (int)$options['limit'];
}

// Add skip if specified
if (isset($options['skip'])) {
$command['skip'] = (int)$options['skip'];
}

// Add maxTimeMS if specified
if (isset($options['maxTimeMS'])) {
$command['maxTimeMS'] = (int)$options['maxTimeMS'];
}

try {
$result = $this->query($command);
return (int)$result;
} catch (Exception $e) {
return 0;
}
Comment on lines +732 to +738
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Don’t swallow exceptions in count(); let them surface or gate by an option

Returning 0 on any error hides real issues and is inconsistent with other methods that throw. Prefer bubbling the exception, or make suppression opt-in (e.g., options['suppressExceptions']).

-        try {
-        $result = $this->query($command);
-          return (int)$result;
-        } catch (Exception $e) {
-            return 0;
-        }
+        if (!empty($options['suppressExceptions'])) {
+            try {
+                return (int) $this->query($command);
+            } catch (Exception $e) {
+                return 0;
+            }
+        }
+        return (int) $this->query($command);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
$result = $this->query($command);
return (int)$result;
} catch (Exception $e) {
return 0;
}
if (!empty($options['suppressExceptions'])) {
try {
return (int) $this->query($command);
} catch (Exception $e) {
return 0;
}
}
return (int) $this->query($command);
🤖 Prompt for AI Agents
In src/Client.php around lines 732 to 737, the count() implementation currently
catches all Exceptions and returns 0 which swallows real errors; change it to
either let exceptions bubble (remove the try/catch) so callers receive the
thrown Exception, or implement an options flag (e.g.,
$this->options['suppressExceptions'] or a method parameter) that, when true,
returns 0 on error but otherwise rethrows the caught Exception; ensure any added
flag default preserves current behavior only if intentionally desired and update
the method signature/docblock accordingly.

}

/**
Expand Down
89 changes: 89 additions & 0 deletions tests/MongoTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -261,4 +261,93 @@ public function testUpsert()
self::assertEquals('USA', $documents[1]->country);
self::assertEquals('English', $documents[1]->language);
}

public function testCountMethod()
{
$collectionName = 'count_test';
$this->getDatabase()->createCollection($collectionName);

$documents = [];
for ($i = 1; $i <= 30; $i++) {
$documents[] = [
'name' => "Document {$i}",
'number' => $i,
'category' => 'test',
'created_at' => new \DateTime()
];
}

$this->getDatabase()->insertMany($collectionName, $documents);

$total = $this->getDatabase()->count($collectionName, [], []);
self::assertEquals(30, $total);

// Test count with filter (should be 1 for each specific number)
$total = $this->getDatabase()->count($collectionName, ['number' => 15], []);
self::assertEquals(1, $total);

// Test count with range filter (should be 10 for numbers 1-10)
$total = $this->getDatabase()->count($collectionName, ['number' => ['$lte' => 10]], []);
self::assertEquals(10, $total);

// Test count with limit (should be 5 for first 5 documents)
$total = $this->getDatabase()->count($collectionName, [], ['limit' => 5]);
self::assertEquals(5, $total);

// Test count with filter and limit (should be 3 for first 3 documents with number <= 10)
$total = $this->getDatabase()->count($collectionName, ['number' => ['$lte' => 10]], ['limit' => 3]);
self::assertEquals(3, $total);


// Test count with $or operator and comparison (should be 2 documents with number <= 2 OR number >= 29)
$total = $this->getDatabase()->count($collectionName, ['$or' => [['number' => ['$lte' => 2]], ['number' => ['$gte' => 29]]]], []);
self::assertEquals(4, $total);

// Test aggregation count - total documents
$aggregationResult = $this->getDatabase()->aggregate($collectionName, [
['$count' => 'total']
]);
self::assertEquals(30, $aggregationResult->cursor->firstBatch[0]->total);

// Test aggregation count with filter
$filteredAggregationResult = $this->getDatabase()->aggregate($collectionName, [
['$match' => ['number' => ['$lte' => 10]]],
['$count' => 'total']
]);
self::assertEquals(10, $filteredAggregationResult->cursor->firstBatch[0]->total);

// Test aggregation count with limit
$limitedAggregationResult = $this->getDatabase()->aggregate($collectionName, [
['$limit' => 7],
['$count' => 'total']
]);
self::assertEquals(7, $limitedAggregationResult->cursor->firstBatch[0]->total);

// Test aggregation count with group by
$groupedAggregationResult = $this->getDatabase()->aggregate($collectionName, [
['$group' => [
'_id' => '$category', // Group by category
'count' => ['$sum' => 1] // Count of documents in the group
]]
]);
self::assertEquals(30, $groupedAggregationResult->cursor->firstBatch[0]->count);
self::assertEquals('test', $groupedAggregationResult->cursor->firstBatch[0]->_id);

// Test aggregation count with $or operator
$orAggregationResult = $this->getDatabase()->aggregate($collectionName, [
['$match' => ['$or' => [['number' => 5], ['number' => 15], ['number' => 25]]]],
['$count' => 'total']
]);
self::assertEquals(3, $orAggregationResult->cursor->firstBatch[0]->total);

// Test aggregation count with complex $or and range
$complexOrAggregationResult = $this->getDatabase()->aggregate($collectionName, [
['$match' => ['$or' => [['number' => ['$lte' => 3]], ['number' => ['$gte' => 28]]]]],
['$count' => 'total']
]);
self::assertEquals(6, $complexOrAggregationResult->cursor->firstBatch[0]->total);


$this->getDatabase()->dropCollection($collectionName);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}