27 votes

Meilleure façon de faire un "JOIN" un-à-plusieurs dans CouchDB

Je suis à la recherche d'un équivalent CouchDB aux "jointures SQL".

Dans mon exemple, il y a des documents CouchDB qui sont des éléments de liste :

{ "type" : "el", "id" : "1", "content" : "first" } 
{ "type" : "el", "id" : "2", "content" : "second" } 
{ "type" : "el", "id" : "3", "content" : "third" } 

Il existe un document qui définit la liste :

{ "type" : "list", "elements" : ["2","1"] , "id" : "abc123" }

Comme vous pouvez le constater, le troisième élément a été supprimé, il ne fait plus partie de la liste. Il ne doit donc pas faire partie du résultat. Maintenant, je veux une vue qui retourne les éléments de contenu en incluant le bon ordre.

Le résultat pourrait être :

{ "content" : ["second", "first"] }

Dans ce cas, l'ordre des éléments est déjà ce qu'il devrait être. Un autre résultat possible :

{ "content" : [{"content" : "first", "order" : 2},{"content" : "second", "order" : 1}] }

J'ai commencé à écrire la fonction map :

map = function (doc) {
  if (doc.type === 'el') {
    emit(doc.id, {"content" : doc.content}); //emit the id and the content
    exit;
  }
  if (doc.type === 'list') {
    for ( var i=0, l=doc.elements.length; i<l; ++i ){
      emit(doc.elements[i], { "order" : i }); //emit the id and the order
    }
  }
}

C'est le plus loin que je puisse aller. Pouvez-vous corriger mes erreurs et écrire une fonction de réduction ? N'oubliez pas que le troisième document ne doit pas faire partie du résultat.

Bien sûr, vous pouvez aussi écrire une autre fonction de carte. Mais la structure des documents (un document d'élément de définition et un document d'entrée pour chaque entrée) ne peut pas être modifiée.


EDIT : Ne manquez pas le commentaire de JasonSmith à sa réponse, où il décrit comment faire plus court.

42voto

JasonSmith Points 34470

Merci ! C'est un excellent exemple à montrer Les nouveautés de CouchDB 0.11 fonctionnalités !

Vous devez utiliser la fonction fetch-related-data pour référencer des documents dans la vue. En option, pour un JSON plus pratique, utilisez un fichier _list fonction pour nettoyer les résultats. Voir L'article de Couchio sur les "JOIN". pour les détails.

Voici le plan :

  1. Tout d'abord, vous avez une contrainte d'unicité sur votre fichier el documents. Si deux d'entre eux d'entre eux ont id=2, c'est un problème. Il est nécessaire d'utiliser le site _id à la place si id . CouchDB garantira l'unicité, mais aussi , le reste de ce plan requiert _id afin d'extraire les documents par ID.

    { "type" : "el", "_id" : "1", "content" : "first" } 
    { "type" : "el", "_id" : "2", "content" : "second" } 
    { "type" : "el", "_id" : "3", "content" : "third" } 

    Si vous modifiez les documents à utiliser _id est absolument impossible, vous pouvez créer une vue simple pour emit(doc.id, doc) puis de le réinsérer dans un base de données temporaire. Cela convertit id a _id mais ajoute une certaine complexité.

  2. La vue émet {"_id": content_id} des données clés sur [list_id, sort_number] pour "regrouper" les listes avec leur contenu.

    function(doc) {
      if(doc.type == 'list') {
        for (var i in doc.elements) {
          // Link to the el document's id.
          var id = doc.elements[i];
          emit([doc.id, i], {'_id': id});
        }
      }
    }

    Maintenant, il y a une simple liste de el documents, dans l'ordre correct. Vous pouvez utiliser startkey y endkey si vous voulez voir uniquement une liste particulière.

    curl localhost:5984/x/_design/myapp/_view/els
    {"total_rows":2,"offset":0,"rows":[
    {"id":"036f3614aeee05344cdfb66fa1002db6","key":["abc123","0"],"value":{"_id":"2"}},
    {"id":"036f3614aeee05344cdfb66fa1002db6","key":["abc123","1"],"value":{"_id":"1"}}
    ]}
  3. Pour obtenir le el le contenu, l'interrogation avec include_docs=true . Grâce à la magie de _id le el les documents seront chargés.

    curl localhost:5984/x/_design/myapp/_view/els?include_docs=true
    {"total_rows":2,"offset":0,"rows":[
    {"id":"036f3614aeee05344cdfb66fa1002db6","key":["abc123","0"],"value":{"_id":"2"},"doc":{"_id":"2","_rev":"1-4530dc6946d78f1e97f56568de5a85d9","type":"el","content":"second"}},
    {"id":"036f3614aeee05344cdfb66fa1002db6","key":["abc123","1"],"value":{"_id":"1"},"doc":{"_id":"1","_rev":"1-852badd683f22ad4705ed9fcdea5b814","type":"el","content":"first"}}
    ]}

    Remarquez, c'est déjà toute l'information dont vous avez besoin. Si votre client est flexible, vous pouvez analyser les informations à partir de ce JSON. Le prochain en option le reformate simplement pour qu'il corresponde à ce dont vous avez besoin.

  4. Utilisez un _list qui reformate simplement la sortie de la vue. Les gens les utilisent pour produire du XML ou du HTML. le JSON plus pratique.

    function(head, req) {
      var headers = {'Content-Type': 'application/json'};
      var result;
      if(req.query.include_docs != 'true') {
        start({'code': 400, headers: headers});
        result = {'error': 'I require include_docs=true'};
      } else {
        start({'headers': headers});
        result = {'content': []};
        while(row = getRow()) {
          result.content.push(row.doc.content);
        }
      }
      send(JSON.stringify(result));
    }

    Les résultats correspondent. Bien sûr, en production, vous aurez besoin startkey y endkey pour spécifier la liste que vous voulez.

    curl -g 'localhost:5984/x/_design/myapp/_list/pretty/els?include_docs=true&startkey=["abc123",""]&endkey=["abc123",{}]'
    {"content":["second","first"]}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X