====== Document ======
Voici la référence de l'API HTTP de CouchDB en matière de Documents.
===== Convention de nommage =====
Un document est tout simplement un objet JSON.
Voici un exemple :
{
"_id": "j-aime-le-chocolat",
"_rev": "1-1915017252",
"Subject": "J'aime le chocolat",
"Author": "Arthur",
"PostedDate": "16/09/2009",
"Tags": ["chocolat", "gâteau", "cuisine"],
"Body": "Je me suis rendu compte aujourd'hui que j'aimais le chocolat, et surtout les gâteaux au chocolat."
}
Il n'y a pas de limitations : tant que l'objet JSON est valide, cela peut être un document.
Un autre exemple plus complexe :
{
"_id": "facture-2009-0658",
"_rev": "1-3344523300",
"Type": "Facture",
"Numero": "2009-0658",
"Date": "16/09/2009",
"Validee": true,
"Client": {
"Nom": "SARL & Co",
"Adresse": "1 rue de la Poste, 75001 Paris",
"Telephone": "01 02 03 04 05"
},
"Lignes": [
{ "Designation": "Super Machine", "PrixUnitaire": "123.76", "Quantité": 1, "MontantHT": "123.76" },
{ "Designation": "Pièce 654", "PrixUnitaire": "10.00", "Quantité": 3, "MontantHT": "30.00" }
],
"TotalHT": "153.76",
"Commentaire": "La facture est HT car mon comptable est en prison..."
}
==== Champs spéciaux ====
CouchDB se réserve quelques champs spéciaux. Ils commencent par "_" (le tiret de bas, l'underscore).
=== _id ===
C'est l'identifiant unique du document. Deux documents ayant le même ID au sein de la même base de données sont considérés comme étant les mêmes.
Le champs "_id" peuvent être :
* définis automatiquement par CouchDB (par exemple : "248e317fc1ea4928342b596de5449e0b")
* définis par vous : vos propres ID uniques ou des combinaisons de champs rendant l'ID unique pour chaque document (voir les deux exemples ci-dessus)
Le champs "_id" accepte en valeur une chaîne de caractère quelconque. Toutefois, il est recommandé de n'utiliser que **[a-zA-Z0-9_-]** c'est à dire les caractères non accentués de **a** à **z**, de **A** à **Z**, de **0** à **9**, **_**, **-** et **/** car l'utilisation d'autres caractères Unicode n'est ni documenté, ni testé.
=== _rev ===
C'est l'identifiant de la révision du document. Quand on travaille sur un document, il faut savoir sur quelle révision on travaille pour y appliquer les changements et régler les éventuels conflits (le "on" désignant vous-même et CouchDB) ; c'est le rôle de ce champs.
Le champs "_rev" est défini automatiquement par CouchDB.
=== Les autres ===
Il y a des champs utilisés qu'occasionnellement :
* "_revisions" : affiche une liste des révisions disponibles
* "_revs_info" : affiche l'historique des numéros de révisions et leur statut.
Sinon, il n'y a pas d'autres champs spéciaux, mais il pourra y en avoir. Donc il est recommandé de ne pas préfixer ses noms de champs par "_" afin de ne pas créer de futurs conflits.
==== URL ====
Chaque document a une URL, utilisée pour les actions directes, de la forme :
http://votre_serveur:5984/votre-base-de-donnee/votre-id-de-document
Quand le caractère **/** est présent dans l'id du document, il doit être encodé en **%2F** pour être utilisé dans une URL. Dans le cas des documents définissant les [[documentation/api/view|vues]] ("_design/nom-du-design"), le slash peut être utilisé tel quel juste après "_design" mais doit être encodé s'il est aussi présent après.
anniversaires-16/09/2009 => http://votre_serveur:5984/votre-base-de-donnee/anniversaires-16%2F09%2F2009
_design/nom-du-design => http://votre_serveur:5984/votre-base-de-donnee/_design/nom-du-design
_design/essai-du-16/09/2009 => http://votre_serveur:5984/votre-base-de-donnee/_design/essai-du-16%2F09%2F2009
===== Accéder aux documents =====
==== Accès simple : GET ====
Pour récupérer le contenu d'un document, faites une requête **GET** sur l'URL du document :
GET /base-de-donnee/248e317fc1ea4928342b596de5449e0b HTTP/1.0
Host: 127.0.0.1:5984
Accept: application/json
La réponse du serveur :
HTTP/1.1 200 OK
Server: CouchDB/0.9.0 (Erlang OTP/R12B)
Etag: "4-4275583169"
Date: Thu, 17 Sep 2009 09:13:18 GMT
Content-Type: application/json
Content-Length: 98
Cache-Control: must-revalidate
{"_id":"248e317fc1ea4928342b596de5449e0b","_rev":"4-4275583169","Type":"Client","Nom":"SARL & Co"}
On notera que dans les headers retournés, le champs **Etag** contient la révision actuelle du document (attention, ne figure pas forcément dans les headers des requêtes **GET** avec paramètres).
==== Accès avancé : GET ====
Des paramètres peuvent être passés après l'URL utilisée par la requête **GET** :
http://votre_serveur:5984/votre-base-de-donnee/votre-id-de-document?parametre_1=valeur_1¶metre_2=valeur_2
=== Paramètre rev ===
Si la [[revision|révision]] est disponible, **rev=identifiant_de_revision** retourne le document tel qu'il était à ce moment.
Si le statut de la révision demandée est **missing** le retour sera (pour par exemple la révision "2-1971751410") :
HTTP/1.1 500 Internal Server Error
Server: CouchDB/0.9.0 (Erlang OTP/R12B)
Date: Thu, 17 Sep 2009 11:50:15 GMT
Content-Type: application/json
Content-Length: 66
Cache-Control: must-revalidate
{"error":"{not_found,missing}","reason":"{2,<<\"1971751410\">>}"}
=== Paramètre revs ===
**revs=true** donne la liste des [[revision|révisions]] du document dans un champs ajouté "_revisions". Exemple de retour :
{
"_id": "248e317fc1ea4928342b596de5449e0b",
"_rev": "4-4275583169",
"type": "Client",
"Nom": "SARL & Co",
"_revisions": {
"start": 4,
"ids": ["4275583169", "3094848030", "1971751410", "3934541355"]
}
}
Les révisions affichées ne sont pas forcément disponibles : la base peut avoir été compactée (retirant alors les anciennes révisions), la révision peut n'être disponible que sur un autre serveur dans le cas de réplication... Voir la page sur les [[revision|révision]].
=== Paramètre revs_info ===
**revs_info=true** donne la liste des [[revision|révisions]] du document ainsi que leur statut dans un champs ajouté "_revs_info". Exemple de retour :
{
"_id": "248e317fc1ea4928342b596de5449e0b",
"_rev": "4-4275583169",
"Type": "Client",
"Nom": "SARL & Co",
"_revs_info": [
{"rev":"4-4275583169", "status":"available"},
{"rev":"3-3094848030", "status":"missing"},
{"rev":"2-1971751410", "status":"missing"},
{"rev":"1-3934541355", "status":"deleted"}
]
}
==== Accès simple : HEAD ====
On peut aussi faire une requête **HEAD**, de manière similaire à **GET**, pour n'obtenir que les headers renvoyés par **GET** (ce qui peut être utile) sans le document lui-même.
===== Enregistrer des documents =====
Pour créer des documents vous pouvez utiliser des requêtes **PUT** ou **POST**. Pour modifier un document, seule la requête **PUT** est utilisable.
==== Créer avec POST ====
Une requête **POST** permet de créer un document en laissant CouchDB s'occuper de l'ID.
Il est recommandé dès que possible d'éviter l'utilisation de **POST** car les proxy et autres intermédiaires réseaux renvoient occasionnellement ces requêtes ce qui peut entraîner la création de doublons non désirés. Aussi, le processus de création d'ID est plutôt coûteux pour CouchDB, il vaut mieux déterminer ces ID côté client (quitte à en demander un certain nombre d'un coup à CouchDB) et d'utiliser une requête **PUT**.
On utilise l'URL de la base de donnée et on passe le document JSON en données.
Exemple de requête :
POST /test/ HTTP/1.1
Host: 127.0.0.1:5985
Accept: application/json
Content-Length: 48
Content-Type: application/json; charset=UTF-8
{"Type":"Client","Nom":"SARL Chauffage au Bois"}
HTTP/1.1 201 Created
Server: CouchDB/0.9.0 (Erlang OTP/R12B)
Location: http://127.0.0.1:5985/test/6dafefb3c0adb84e78a73711440d44fc
Date: Thu, 17 Sep 2009 12:22:22 GMT
Content-Type: application/json
Content-Length: 73
Cache-Control: must-revalidate
{"ok":true,"id":"6dafefb3c0adb84e78a73711440d44fc","rev":"1-2474629244"}
Le serveur renvoie le code HTTP **201 Created** ainsi que l'ID et la révision du document créé.
==== Créer avec PUT ====
Une requête **PUT** permet de créer un document en spécifiant explicitement l'ID à utiliser. Ce cas est juste un cas particulier d'utilisation de **PUT** dans laquelle la révision n'est pas spécifié (puisque le document est nouveau).
On utilise l'URL du document, c'est à dire contenant l'ID que vous donnez.
Exemple de requête (nous souhaitons que l'ID soit "sarl-chauffage-au-bois") :
PUT /test/sarl-chauffage-au-bois HTTP/1.1
Host: 127.0.0.1:5985
Accept: application/json
Content-Length: 48
Content-Type: application/json; charset=UTF-8
{"Type":"Client","Nom":"SARL Chauffage au Bois"}
HTTP/1.1 201 Created
Server: CouchDB/0.9.0 (Erlang OTP/R12B)
Etag: "1-3121202954"
Date: Thu, 17 Sep 2009 12:42:57 GMT
Content-Type: application/json
Content-Length: 63
Cache-Control: must-revalidate
{"ok":true,"id":"sarl-chauffage-au-bois","rev":"1-3121202954"}
Le serveur renvoie le code HTTP **201 Created** ainsi que l'ID et la révision du document créé.
==== Modifier avec PUT ====
Une requête **PUT** permet de modifier un document existant. On doit spécifier l'ID du document en question et la révision du document que l'on souhaite modifier.
On utilise l'URL du document, c'est à dire contenant l'ID du document. CouchDB obtient l'ID ainsi.
Pour la révision, on l'insère dans le document sous le champs "_rev". Y placer un champs "_id" avec l'ID n'est pas obligatoire.
Exemple de requête (nous modifions le document ayant l'ID "sarl-chauffage-au-bois" et la révision "1-3121202954") :
PUT /test/sarl-chauffage-au-bois HTTP/1.1
Host: 127.0.0.1:5985
Accept: application/json
Content-Length: 115
Content-Type: application/json; charset=UTF-8
{"_id":"sarl-chauffage-au-bois","_rev":"1-3121202954","Type":"Client","Nom":"SARL Chauffage au Bois & Frères"}
HTTP/1.1 201 Created
Server: CouchDB/0.9.0 (Erlang OTP/R12B)
Etag: "2-1198331443"
Date: Thu, 17 Sep 2009 12:56:12 GMT
Content-Type: application/json
Content-Length: 63
Cache-Control: must-revalidate
{"ok":true,"id":"sarl-chauffage-au-bois","rev":"2-1198331443"}
Le serveur renvoie le code HTTP **201 Created** ainsi que l'ID et la nouvelle révision du document.
Si la révision du document ne correspond pas à la révision de la version actuelle du document sur le serveur, le serveur répondra :
HTTP/1.1 409 Conflict
Server: CouchDB/0.9.0 (Erlang OTP/R12B)
Date: Thu, 17 Sep 2009 13:03:43 GMT
Content-Type: application/json
Content-Length: 58
Cache-Control: must-revalidate
{"error":"conflict","reason":"Document update conflict."}
Les cas de conflits lors de la modification des documents sont abordés sur la page [[conflits]].
==== Modifier avec PUT : les paramètres ====
Les paramètres sont passés après l'URL du document, de la même manière que pour **GET** :
http://votre_serveur:5984/votre-base-de-donnee/votre-id-de-document?parametre_1=valeur_1¶metre_2=valeur_2
===Paramètre batch===
Le paramètre **batch=ok** permet d'atteindre un débit d'écriture plus élevé au prix d'une garantie de succès inférieure. Quand un **PUT** (marche aussi avec **POST**) est envoyé en utilisant cette option, le document n'est pas immédiatement écrit sur le disque. Au contraire, il est stockée en mémoire (par utilisateur) pour une seconde ou deux (ou jusqu'à que le nombre de documents en mémoire atteint un certain point). Dès que le seuil est atteint, les documents se sont écrits sur le disque. Au lieu d'attendre que le document soit écrit sur le disque pour répondre, CouchDB renvoie le code HTTP **202 Accepted** immédiatement.
Le paramètre batch=ok n'est pas adapté pour des données cruciales, mais il est idéal pour des applications de logging, par exemple, qui peuvent accepter le risque qu'une faible proportion de modifications soit perdue lors d'un crash. L'écriture des documents en mémoire sur le disque peut également être faite manuellement en utilisant l'API _ensure_full_commit.
===== Autres opérations =====
==== Supprimer un document ====
Pour supprimer un document, faites une requête **DELETE** sur l'URL du document, en y ajoutant le paramètre "rev" contenant la révision actuelle du document.
DELETE /test/6dafefb3c0adb84e78a73711440d44fc?rev=1-2474629244 HTTP/1.1
Host: 127.0.0.1:5985
Accept: application/json
HTTP/1.1 200 OK
Server: CouchDB/0.9.0 (Erlang OTP/R12B)
Etag: "2-4290809874"
Date: Thu, 17 Sep 2009 14:18:00 GMT
Content-Type: application/json
Content-Length: 73
Cache-Control: must-revalidate
{"ok":true,"id":"6dafefb3c0adb84e78a73711440d44fc","rev":"2-4290809874"}
Le serveur retourne un nouveau numéro de révision correspondant à la suppression.
Vous pouvez aussi procéder en passant la révision via le header Etag “If-Match” :
DELETE /test/6dafefb3c0adb84e78a73711440d44fc HTTP/1.1
Host: 127.0.0.1:5985
Accept: application/json
If-Match: "1-2474629244"
=== Erreurs possibles ===
Si vous ne spécifiez pas la révision du document en paramètre de la requête (ou si vous spécifiez un qui n'est pas la révision actuelle du document), le serveur vous renverra le code HTTP **409 Conflict** avec comme contenu :
{"error":"conflict","reason":"Document update conflict."}
Si vous essayer de supprimer un document déjà supprimé, le serveur vous renverra le code HTTP **404 Object Not Found** avec comme contenu :
{"error":"not_found","reason":"deleted"}
==== Copier un document ====
Pour copier un document, faites une requête **COPY** sur l'URL du document source. Vous devez spécifier l'ID du document cible à créer via le header "Destination".
La requête **COPY** est une extension non standard de HTTP. Cela permet de dupliquer les documents sans échanger leur contenu avec CouchDB.
Il n'est pas possible de copier des documents entre différentes base de données.
Exemple :
COPY /votre-base-de-donnee/votre-id-de-document HTTP/1.1
Destination: votre-id-de-document-nouveau
HTTP/1.1 201 Created
Server: CouchDB/0.9.0 (Erlang OTP/R12B)
Etag: "1-7865379365"
Date: Thu, 17 Sep 2009 14:18:00 GMT
Content-Type: application/json
Content-Length: 68
Cache-Control: must-revalidate
{"ok":true,"id":"votre-id-de-document-nouveau","rev":"1-7865379365"}
Si vous souhaitez remplacer un document existant, vous devez spécifier la révision actuelle du document cible avec un paramètre "rev" dans le header "Destination" :
COPY /votre-base-de-donnee/votre-id-de-document HTTP/1.1
Destination: votre-id-de-document-nouveau?rev=id-de-revision
La réponse du serveur est la même.
==== Déplacer un document ====
Pendant une période de 6 mois, entre les versions 0.8 et 0.9, la version de développement de CouchDB a inclus la méthode **MOVE**, non standard. Comme **MOVE** n'est que **COPY** suivit de **DELETE** et que CouchDB ne peut pas garantir une atomicité raisonnable entre les requêtes **COPY** et **MOVE** sur un seul ou sur plusieurs noeuds, cela a été retiré avant la sortie de la version 0.9 de CouchDB.
===== Attachements =====
FIXME