W3docs

Mise à jour MongoDB

Apprenez à mettre à jour des documents MongoDB en Python avec update_one(), update_many(), upsert et les opérateurs $set, $inc et $push.

PyMongo fournit deux méthodes principales pour modifier des documents dans une collection : update_one() modifie le premier document correspondant à un filtre, et update_many() modifie tous les documents correspondants. Ces deux méthodes utilisent les opérateurs de mise à jour de MongoDB — des instructions comme $set, $inc et $push — pour décrire précisément ce qui doit changer, laissant le reste du document intact.

Ce chapitre couvre :

  • La connexion à MongoDB avec PyMongo
  • update_one() — modifier un seul document
  • update_many() — modifier plusieurs documents à la fois
  • Les opérateurs de mise à jour : $set, $unset, $inc, $push, $pull
  • La mise à jour de champs imbriqués avec la notation pointée
  • Les upserts — insertion ou mise à jour en une seule étape
  • La vérification de ce qui a été modifié via l'objet résultat

Si vous n'avez pas encore inséré de documents, lisez d'abord MongoDB Insert. Pour la syntaxe de filtrage, consultez MongoDB Query.

Connexion à MongoDB

Installez le pilote si ce n'est pas déjà fait :

pip install pymongo

Puis connectez-vous à une base de données et à une collection :

import pymongo

client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["mydatabase"]
mycol = db["mycollection"]

MongoClient est paresseux — il n'ouvre pas réellement de socket avant la première opération. La base de données et la collection sont créées automatiquement la première fois qu'un document y est écrit.

Mise à jour d'un seul document

update_one(filter, update) trouve le premier document correspondant à filter et lui applique update.

result = mycol.update_one(
    {"name": "Alice"},       # filter: which document to change
    {"$set": {"age": 31}}    # update: what to change
)

print(result.matched_count)   # 1 if a document was found
print(result.modified_count)  # 1 if a value actually changed

L'opérateur $set écrase les champs listés et laisse tous les autres champs du document exactement tels quels. Sans $set, le second argument remplacerait l'intégralité du document, ce qui est rarement souhaité.

Pourquoi matched_count et modified_count peuvent différer

Si le document a déjà age: 31, MongoDB le trouve mais n'écrit rien. Dans ce cas, matched_count vaut 1 et modified_count vaut 0. Vérifiez toujours modified_count pour confirmer qu'une vraie écriture a eu lieu.

Mise à jour de plusieurs documents

update_many(filter, update) applique la même mise à jour à tous les documents correspondant au filtre.

result = mycol.update_many(
    {"status": {"$ne": "closed"}},   # every document where status != "closed"
    {"$set": {"status": "open"}}
)

print(f"Matched:  {result.matched_count}")
print(f"Modified: {result.modified_count}")

update_many() est atomique par document, mais pas à l'échelle de plusieurs documents. Chaque document individuel est modifié de manière atomique, mais d'autres clients peuvent lire ou écrire entre les mises à jour individuelles au sein d'un même appel update_many().

Opérateurs de mise à jour

MongoDB propose un ensemble d'opérateurs de mise à jour permettant d'exprimer des modifications précises sans avoir à envoyer l'intégralité du document sur le réseau.

$set — définir des valeurs de champ

# Set one field
mycol.update_one({"name": "Alice"}, {"$set": {"city": "Boston"}})

# Set multiple fields at once
mycol.update_one({"name": "Alice"}, {"$set": {"city": "Boston", "active": True}})

$unset — supprimer un champ

# Remove the "temporary" field from the matching document
mycol.update_one({"name": "Alice"}, {"$unset": {"temporary": ""}})

La valeur que vous assignez au champ dans $unset est sans importance — MongoDB l'ignore. La convention est d'utiliser une chaîne vide.

$inc — incrémenter ou décrémenter un nombre

# Add 5 to the "score" field (creates it at 5 if it does not exist)
mycol.update_one({"name": "Alice"}, {"$inc": {"score": 5}})

# Subtract 1
mycol.update_one({"name": "Alice"}, {"$inc": {"score": -1}})

$inc est sûr pour les compteurs car il s'agit d'une seule opération atomique — deux incréments simultanés seront tous deux appliqués correctement.

$push — ajouter à un array

# Add a tag to the "tags" array (creates the array if it does not exist)
mycol.update_one({"name": "Alice"}, {"$push": {"tags": "python"}})

$pull — supprimer des éléments d'un array

# Remove all occurrences of "python" from the "tags" array
mycol.update_one({"name": "Alice"}, {"$pull": {"tags": "python"}})

Mise à jour de documents imbriqués

Utilisez la notation pointée pour accéder aux documents imbriqués sans réécrire l'intégralité de l'objet imbriqué.

Considérez un document de cette forme :

{
  "name": "Alice",
  "address": {
    "city": "New York",
    "state": "NY"
  }
}

Pour modifier uniquement le champ state à l'intérieur de address :

mycol.update_one(
    {"name": "Alice"},
    {"$set": {"address.state": "NJ"}}
)

Le champ city à l'intérieur de address n'est pas touché. Vous pouvez descendre autant de niveaux que votre schéma l'exige — par exemple "address.geo.lat".

Upsert : insertion ou mise à jour en une seule étape

Un upsert indique à MongoDB : « mets à jour ce document s'il existe ; insère-le sinon. » Passez upsert=True comme argument nommé :

result = mycol.update_one(
    {"name": "Bob"},
    {"$set": {"age": 25, "status": "new"}},
    upsert=True
)

if result.upserted_id:
    print(f"Inserted new document with _id: {result.upserted_id}")
else:
    print("Updated an existing document")

Lorsque MongoDB insère un nouveau document via un upsert, l'attribut upserted_id de l'objet résultat contient le nouvel _id. Lorsqu'il met à jour un document existant, upserted_id vaut None.

update_many() accepte également upsert=True. Si aucun document ne correspond, MongoDB insère un seul nouveau document — il n'insère jamais plusieurs documents à partir d'un seul upsert.

Inspection de l'objet résultat

update_one() et update_many() retournent tous deux un objet UpdateResult avec trois attributs utiles :

AttributDescription
matched_countNombre de documents correspondant au filtre
modified_countNombre de documents réellement modifiés
upserted_id_id du document nouvellement inséré (upsert uniquement) ; None sinon
result = mycol.update_many(
    {"role": "guest"},
    {"$set": {"role": "member"}}
)

print(f"Matched:  {result.matched_count}")
print(f"Modified: {result.modified_count}")
print(f"Upserted: {result.upserted_id}")

Erreurs fréquentes

Oublier un opérateur de mise à jour remplace le document. Cet appel supprime tous les champs sauf _id et remplace le document par seulement age: 31 :

# Dangerous — replaces the whole document
mycol.update_one({"name": "Alice"}, {"age": 31})

Encadrez toujours vos modifications dans un opérateur ($set, $inc, etc.).

Filtrer par _id nécessite un ObjectId. Les identifiants de documents sont stockés en tant qu'objets ObjectId, et non en tant que chaînes simples :

from bson.objectid import ObjectId

mycol.update_one(
    {"_id": ObjectId("64a1f2c3d4e5f6a7b8c9d0e1")},
    {"$set": {"verified": True}}
)

Passer l'identifiant en tant que chaîne simple ne correspondra à rien et ne fera rien silencieusement.

Étapes suivantes

  • MongoDB Delete — supprimer des documents avec delete_one() et delete_many()
  • MongoDB Find — récupérer des documents et filtrer les résultats
  • MongoDB Query — opérateurs et modèles de requête avancés
Was this page helpful?