La meilleure façon de faire un à plusieurs "joindre" dans CouchDB

je cherche un CouchDB équivalent à"SQL joins".

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 y a un document qui définit la liste:

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

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

le résultat pourrait être:

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

Dans ce cas, l'ordre des éléments est déjà comme il se doit. Un autre résultat possible:

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

j'ai commencé à écrire la fonction de carte:

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
    }
  }
}

Je ne peux pas aller plus loin. Pouvez-vous corriger mes erreurs et d'écrire une fonction de réduction? Rappelez-vous que le troisième document ne doit pas faire partie du résultat.

bien sûr que vous pouvez écrivez une fonction de carte différente aussi. Mais la structure des documents (un é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 JasonSmith commentaire de sa réponse, où il décrit comment faire plus court.

33
demandé sur mit 2010-06-13 22:43:04

1 réponses

Merci! C'est un bon exemple pour montrer la nouvelle version de CouchDB 0.11 de les fonctionnalités !

Vous devez utiliser le fetch-option de données, de documents de référence dans la vue. en option, pour plus de commodité, JSON, l'utilisation d'un _list la fonction de nettoyer les résultats. Pour plus de détails, voir couchio's writeup sur "JOIN"s .

voici le plan:

  1. tout d'abord, vous avez un contenu unique sur vos documents el . Si deux de ils ont id=2, c'est un problème. Il est nécessaire d'utiliser le champ _id à la place de id . CouchDB garantira l'unicité, mais aussi, le reste de ce plan nécessite _id pour aller chercher des documents par carte D'identité.

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

    si changer les documents pour utiliser _id est absolument impossible, vous pouvez créer une vue simple pour emit(doc.id, doc) et ensuite réinsérer cela dans un base de données temporaire. Cela convertit id en _id mais ajoute une certaine complexité.

  2. Le point de vue émet {"_id": content_id} données saisies sur [list_id, sort_number] , de "touffe" 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 documents el , dans le bon ordre. Vous pouvez utiliser startkey et endkey si vous voulez voir seulement un particulier liste.

    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 contenu el , interrogez avec include_docs=true . Grâce à la magie de _id , les documents el se chargeront.

    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"}}
    ]}
    

    avis, c'est déjà toutes les informations dont vous avez besoin. Si votre client est flexible, vous pouvez extraire l'information de ce JSON. Le suivant optionnel step le reformate simplement pour correspondre à ce dont vous avez besoin.

  4. utilisez une fonction _list , qui reformate simplement la sortie de vue. Les gens les utilisent pour produire XML ou HTML cependant nous ferons le JSON est 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, dans la production, vous aurez besoin de startkey et endkey pour spécifier la liste que vous souhaitez.

    curl -g 'localhost:5984/x/_design/myapp/_list/pretty/els?include_docs=true&startkey=["abc123",""]&endkey=["abc123",{}]'
    {"content":["second","first"]}
    
50
répondu JasonSmith 2017-05-23 12:34:31