Skip to content

Commit

Permalink
fix(db): issue with results consistency
Browse files Browse the repository at this point in the history
  • Loading branch information
hippothomas committed Jan 28, 2024
1 parent f40419d commit e88fcfb
Showing 1 changed file with 91 additions and 15 deletions.
106 changes: 91 additions & 15 deletions src/Service/MongoDB.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use MongoDB\BSON\Regex;
use MongoDB\Collection;
use MongoDB\Client as Mongo;
use MongoDB\Database;
use MongoDB\Driver\CursorInterface;
use Psr\Log\LoggerInterface;

Expand All @@ -19,24 +20,33 @@ public function __construct(
) { }

/**
* Retrieves a MongoDB collection or returns false on failure
* @return Collection|false The MongoDB collection or false if the connection fails.
* Retrieves a MongoDB database or returns false on failure
* @return Database|false The MongoDB database or false if the connection fails.
*/
private function getCollection(): Collection|false
private function getDb(): Database|false
{
// Create a new MongoDB client instance
$mongo = new Mongo($this->mongoDbUrl);

// Test the connection to the MongoDB server and return the collection
// Test the connection to the MongoDB server and return the database
try {
$mongo->{$this->mongoDbName}->command(['ping' => 1]);
return $mongo->{$this->mongoDbName}->journal;
return $mongo->{$this->mongoDbName};
} catch (Exception $e) {
$this->logger->error('[MongoDB] Exception: {exception}', [
'exception' => $e->getMessage(),
]);
}
return false;
}

/**
* Retrieves a MongoDB collection or returns false on failure
* @return Collection|false The MongoDB collection or false if the connection fails.
*/
private function getCollection(): Collection|false
{
return $this->getDb()?->journal ?? false;
}

/**
Expand All @@ -45,7 +55,7 @@ private function getCollection(): Collection|false
*/
public function isConnected(): bool
{
return $this->getCollection() !== false;
return $this->getDb() !== false;
}

/**
Expand Down Expand Up @@ -120,15 +130,21 @@ public function findOne(int $user_id, DateTime $date): array|false
*/
public function retrieveUserNutritionData(int $user_id, array $date_list, array $fields_group, int $sort = -1, int $limit = 100, int $offset = 0, array $filters_group = []): CursorInterface|false
{
$collection = $this->getCollection();
if (!$collection) return false;
// Build query for the View
$aggregate_query = $this->getNutritionAggregateQuery();

// Check if the view exist otherwise create it
$view = $this->getView("nutrition", "journal", $aggregate_query);
if (!$view) return false;

// Prepare the query
$match = ['user_id' => $user_id];

// Prepare the date list for the request
if (empty($date_list)) return false;
$dates = [];
foreach ($date_list as $date) {
$dates[] = [ 'entry.dateTime' => new Regex("{$date}.*") ];
$dates[] = [ 'dateTime' => new Regex("{$date}.*") ];
}
$match['$or'] = $dates;

Expand All @@ -143,18 +159,15 @@ public function retrieveUserNutritionData(int $user_id, array $date_list, array
// Add filters for the request
$match = array_merge($match, $filters_group);

// Search into the collection and return results as an array, if successfully found
// Search into the view and return results as an array, if successfully found
try {
return $collection->aggregate([
return $view->aggregate([
[
'$match' => $match
],
[
'$sort' => [ 'timestamp' => -1 ]
],
[
'$group' => [
'_id' => '$entry.dateTime',
'_id' => '$dateTime',
'data' => [
'$first' => !empty($fields) ? $fields : '$$ROOT.nutrition'
]
Expand Down Expand Up @@ -182,4 +195,67 @@ public function retrieveUserNutritionData(int $user_id, array $date_list, array
}
return false;
}

/**
* Get or create a MongoDB view
* @param string $view_name The name of the MongoDB view
* @param string $collection_name The name of the collection on which the view is based
* @param array $aggregate_query An array representing the aggregation pipeline to create the view
* @return Collection|false Returns the MongoDB view (Collection) if it exists or was successfully created. Returns false on failure
*/
private function getView(string $view_name, string $collection_name = "", array $aggregate_query = []): Collection|false
{
$db = $this->getDb();
if (!$db) return false;

// Check if the view exist
$collections = $db->listCollections();
foreach ($collections as $collection) {
if ($collection->getType() === "view" && $collection->getName() === $view_name) {
return $db->{$view_name};
}
}
if (empty($aggregate_query) || empty($collection_name)) return false;

// Create the view if it doesn't exist
try {
$db->command([
'create' => $view_name,
'viewOn' => $collection_name,
'pipeline' => $aggregate_query
]);
} catch (Exception $e) {
$this->logger->error('[MongoDB] Exception: {exception}', [
'exception' => $e->getMessage(),
]);
return false;
}
return $this->getView($view_name);
}

private function getNutritionAggregateQuery(): array
{
return [
[
'$sort' => [ 'timestamp' => -1 ]
],
[
'$group' => [
'_id' => [
'user_id' => '$user_id',
'dateTime' => '$entry.dateTime'
],
'nutrition' => [
'$first' => '$$ROOT.nutrition'
],
'dateTime' => [
'$first' => '$$ROOT.entry.dateTime'
],
'user_id' => [
'$first' => '$$ROOT.user_id'
]
]
]
];
}
}

0 comments on commit e88fcfb

Please sign in to comment.