2010-06-13 30 views
32

Tôi đang tìm một tương đương CouchDB với "SQL join".Cách tốt nhất để thực hiện một "nhiều lần" JOIN trong CouchDB

Trong ví dụ của tôi có những tài liệu CouchDB đó là những yếu tố danh sách:

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

Có một tài liệu định nghĩa danh sách:

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

Như bạn có thể thấy các yếu tố thứ ba đã bị xóa, nó không còn là một phần của danh sách nữa. Vì vậy, nó không phải là một phần của kết quả. Bây giờ tôi muốn một khung nhìn trả về các phần tử nội dung bao gồm thứ tự đúng.

Kết quả có thể là:

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

Trong trường hợp này theo thứ tự của các yếu tố là đã như nó phải được. Một kết quả có thể:

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

tôi bắt đầu viết các chức năng bản đồ:

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

Đây là như xa như tôi có thể nhận được. Bạn có thể sửa lỗi của tôi và viết một chức năng giảm? Hãy nhớ rằng tài liệu thứ ba không phải là một phần của kết quả.

Tất nhiên bạn cũng có thể viết chức năng bản đồ khác. Nhưng cấu trúc của các tài liệu (không thể thay đổi tài liệu phần tử xác định và tài liệu nhập cho mỗi mục nhập).


EDIT: Đừng bỏ lỡ nhận xét của JasonSmith về câu trả lời của anh ấy, nơi anh ấy mô tả cách làm điều này ngắn hơn.

Trả lời

50

Cảm ơn bạn! Đây là một ví dụ tuyệt vời để thể hiện CouchDB 0.11's new features!

Bạn phải sử dụng tính năng tìm nạp dữ liệu liên quan đến tài liệu tham chiếu trong chế độ xem. Tùy chọn, để thuận tiện hơn JSON, hãy sử dụng chức năng _list để xóa kết quả. Xem Couchio's writeup on "JOIN"s để biết chi tiết.

Đây là kế hoạch:

  1. Thứ nhất, bạn có một contstraint độc đáo trên el tài liệu của bạn. Nếu hai trong số chúng có id = 2, đó là một vấn đề. Bạn cần sử dụng trường _id thay vì nếu id. CouchDB sẽ đảm bảo tính duy nhất, nhưng cũng có, phần còn lại của gói này yêu cầu _id để tìm nạp tài liệu theo ID.

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

    Nếu thay đổi các tài liệu để sử dụng _id là hoàn toàn không thể, bạn có thể tạo một cái nhìn đơn giản để emit(doc.id, doc) và sau đó tái chèn đó vào một cơ sở dữ liệu tạm thời . Điều này chuyển đổi id thành _id nhưng thêm một số phức tạp.

  2. Chế độ xem phát ra {"_id": content_id} dữ liệu được khóa trên [list_id, sort_number], để "nhóm" các danh sách có nội dung của chúng.

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

    Hiện có danh sách đơn giản là el tài liệu, theo thứ tự đúng. Bạn có thể sử dụng startkeyendkey nếu bạn chỉ muốn xem một danh sách cụ thể.

    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. Để có được el nội dung, truy vấn với include_docs=true. Thông qua sự kỳ diệu của _id, tài liệu el sẽ tải.

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

    Lưu ý, đây là tất cả thông tin bạn cần. Nếu khách hàng của bạn là linh hoạt, bạn có thể phân tích cú pháp thông tin ra khỏi JSON này. bước tiếp theo chỉ cần định dạng lại để khớp với những gì bạn cần.

  4. Sử dụng chức năng _list, chức năng này chỉ định dạng lại đầu ra chế độ xem. Mọi người sử dụng chúng để xuất XML hoặc HTML tuy nhiên chúng tôi sẽ làm cho JSON thuận tiện hơn.

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

    Kết quả phù hợp. Tất nhiên trong sản xuất, bạn sẽ cần startkeyendkey để chỉ định danh sách bạn muốn.

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

Word, đây là một kỹ lưỡng. Công việc tốt jhs! –

+2

Nó là sai lầm dài. Trên thực tế bướC# 2 là một giải pháp hoàn chỉnh, tuy nhiên có, tôi yêu cầu nền chi tiết và cách tùy chọn để thêm tiện lợi ở phía khách hàng. – JasonSmith

+1

URL CouchIO đã thay đổi, đây là URL mới cho cùng một bài viết: http://couchio.tumblr.com/post/446015664/whats-new-in-apache-couchdb-011-part-two – Bdoserror

Các vấn đề liên quan