rekam
rekam

Reputation: 1121

Couchbase View: get documents by keys, sorted

I'm using couchbase 3.0.1 Community Edition (build-1444). I have documents with a date and an array of tags:

{
    // ...
    date_start: '2015-09-25',
    tags: ['tag1', 'tag2'],
    // ...
}

I created a view to match these documents by tags:

function (doc, meta) {
    // some tests to be sure the doc is alright
    // ...
    for (var i = 0, i < doc.tags.length; i += 1) {
        emit(doc.tags[i], null);
    }
}

When creating a query to fetch tags by keys, everything is ok. But now, what is the best way to sort this by date_start descendant?

I saw in the doc (http://docs.couchbase.com/admin/admin/Views/views-querying.html) that:

When using this query option [keys], the output results are not sorted by key. This is because key sorting of these values would require collating and sorting all the rows before returning the requested information.

What if I still would like to sort?

----- EDIT -----

I'm using a limit to fetch only the last five documents with these tags. And that's the point: this limit should retrieve documents by tags but with the date ordered.

Thanks

Upvotes: 2

Views: 485

Answers (2)

Julian Go
Julian Go

Reputation: 4490

Couchbase view results will always be ordered by key so to achieve your query you must have the date_start part of the key.

To query the documents with a particular tag, you could have a map function like this:

function (doc, meta) {
    for (var i = 0; i < doc.tags.length; i += 1) {
        emit(doc.tags[i] + "::" + doc.date_start, docData);
    }
}

and query the view by key range (tag + "::" + current_time, tag + "::" + the_beginning_of_time). docData would be the subset of document data that you need to display in the search results(title,tags,...).

To be able to match documents on multiple tags, a trick would be to emit all the possible combinations of tags(ie. the power set):

function (doc, meta) {
    var combinations = getSortedPowerSet(doc.tags)
    for (var i = 0; i < combinations.length; i += 1) {
        emit(combinations[i].join("::") + "::" + doc.date_start, docData);
    }
}

and query by key range starting at tags.sort().join("::") + "::" + current_time. (Note that when tags is empty it should return the most recent document as expected.)

The powerset is easy to compute in python, it's probably not too hard in node.js, you would just need to enforce a maximum number of tags n per document given that the size of the power set grows exponentially at 2^n.

Upvotes: 0

FuzzyAmi
FuzzyAmi

Reputation: 8157

I dont think there's a simple way of getting what you want, but you could do the following:

  1. Obviously, you could use multiple queries and then intersect your results in your code. This isn't as bad as it sounds: the accuracy of query is already limited to 'eventual consistency' so your results are not accurate to begin with.

  2. Another thing you could do - using a single query - is to emit both the tags AND the date and (again) sort the results in your code.

  3. finally, perhaps this can be done in NIQL - but that would only be production-ready in Couchbase 4.

Upvotes: 0

Related Questions