Mise à jour optimiste des documents versionnés dans MongoDB
Read this article in English Supposons que vous ayez besoin de stocker dans MongoDB des documents provenant d'une source externe comme une file d'attente RabbitMQ ou Kafka. L'ordre dans lequel ces messages sont traités n'est pas garanti, surtout s'il y a plusieurs processus de traitement en parallèle. Afin de garantir de toujours disposer de la dernière version d'un document, et que celle-ci ne soit pas écrasée par une version plus ancienne qui proviendrait d'un autre message ayant été traité plus tard, il est possible d'utiliser un numéro de version. Plus le numéro de version est élevé, plus le document est récent. La source de données externe doit alors inclure le numéro de version du document à chaque message. Ce numéro de version peut être un incrément ou simplement le timestamp auquel la source de données a généré le message. Dans MongoDB, on utilise la méthode updateOne pour mettre à jour un document, mais pour s'assurer qu'on n'écrase pas une version plus récente, on ajoute une condition qui vérifie que le numéro de version du document dans la base de données est inférieur à celui du document que l'on souhaite insérer. use MongoDB\Collection; /** * @param Collection $collection The MongoDB collection * @param int $id The ID of the document to update * @param int $version The version of the new document * @param array $document The new document * @return bool True if the new version have been saved, false if it was outdated */ function optimisticUpsert(Collection $collection, int $id, int $version, array $document): bool { // The document id and version are stored in the document itself $document['_id'] = $id; $document['_version'] = $version; $result = $collection->updateOne( ['_id' => $id], [ ['$replaceWith' => [ '$cond' => [ 'if' => ['$lt' => ['$_version', $version]], 'then' => $document, 'else' => '$$ROOT', ], ]], ], ['upsert' => true], ); return $result->getUpsertedCount() > 0 || $result->getModifiedCount() > 0; } Le serveur MongoDB est assez intelligent pour savoir qu'il n'y a pas de changement lorsque la version stockée était déjà plus récente que celle que l'on souhaitait insérer. Si $result->getUpsertedCount() est supérieur à 0, cela signifie que le document n'existait pas et a été inséré. Si $result->getModifiedCount() est supérieur à 0, cela signifie que le document existait déjà et a été mis à jour. Sinon, cela signifie que la version du document était déjà plus récente que celle que l'on souhaitait insérer. Plus d'informations sur les opérations de mise à jour dans la documentation : Expression $replaceWith. Opérateur $cond. Méthode updateOne.

Supposons que vous ayez besoin de stocker dans MongoDB des documents provenant d'une source externe comme une file d'attente RabbitMQ ou Kafka. L'ordre dans lequel ces messages sont traités n'est pas garanti, surtout s'il y a plusieurs processus de traitement en parallèle.
Afin de garantir de toujours disposer de la dernière version d'un document, et que celle-ci ne soit pas écrasée par une version plus ancienne qui proviendrait d'un autre message ayant été traité plus tard, il est possible d'utiliser un numéro de version. Plus le numéro de version est élevé, plus le document est récent.
La source de données externe doit alors inclure le numéro de version du document à chaque message. Ce numéro de version peut être un incrément ou simplement le timestamp auquel la source de données a généré le message.
Dans MongoDB, on utilise la méthode updateOne
pour mettre à jour un document, mais pour s'assurer qu'on n'écrase pas une version plus récente, on ajoute une condition qui vérifie que le numéro de version du document dans la base de données est inférieur à celui du document que l'on souhaite insérer.
use MongoDB\Collection;
/**
* @param Collection $collection The MongoDB collection
* @param int $id The ID of the document to update
* @param int $version The version of the new document
* @param array $document The new document
* @return bool True if the new version have been saved, false if it was outdated
*/
function optimisticUpsert(Collection $collection, int $id, int $version, array $document): bool
{
// The document id and version are stored in the document itself
$document['_id'] = $id;
$document['_version'] = $version;
$result = $collection->updateOne(
['_id' => $id],
[
['$replaceWith' => [
'$cond' => [
'if' => ['$lt' => ['$_version', $version]],
'then' => $document,
'else' => '$$ROOT',
],
]],
],
['upsert' => true],
);
return $result->getUpsertedCount() > 0 || $result->getModifiedCount() > 0;
}
Le serveur MongoDB est assez intelligent pour savoir qu'il n'y a pas de changement lorsque la version stockée était déjà plus récente que celle que l'on souhaitait insérer.
Si $result->getUpsertedCount()
est supérieur à 0, cela signifie que le document n'existait pas et a été inséré. Si $result->getModifiedCount()
est supérieur à 0, cela signifie que le document existait déjà et a été mis à jour. Sinon, cela signifie
que la version du document était déjà plus récente que celle que l'on souhaitait insérer.
Plus d'informations sur les opérations de mise à jour dans la documentation :
- Expression $replaceWith.
- Opérateur $cond.
- Méthode updateOne.