Reputation: 623
I have a simple view with mapper that emits docs with some keys.
com.couchbase.lite.View view = database.getView(VIEW_NAME);
if (view.getMap() == null) {
Mapper map = new Mapper() {
@Override
public void map(Map<String, Object> document, Emitter emitter) {
if ("user".equals(document.get("type"))) {
emitter.emit(document.get("name"), document);
}
}
};
view.setMap(map, null);
}
having this View, i can than create Queries on it, with certain parameters like setKeys, startKey, endKey, setDescending, setDescending, setSkip and others as described in couchbase manual.
If i write
Query query = view.createQuery();
List<Object> keys = new ArrayList<>();
keys.add("User Name");
query.setKeys(keys);
that query would return all docs matching "User Name" key.
But I couldn't find a simple way to write queries that excludes (omits) docs with certain keys (like opposite to setKeys() function)
one hack was found in ToDoLite Example The code looks like this:
public static Query getQuery(Database database, final String ignoreUserId) {
com.couchbase.lite.View view = database.getView(VIEW_NAME);
if (view.getMap() == null) {
Mapper map = new Mapper() {
@Override
public void map(Map<String, Object> document, Emitter emitter) {
if ("user".equals(document.get("type"))) {
if (ignoreUserId == null ||
(ignoreUserId != null &&
!ignoreUserId.equals(document.get("user_id")))) {
emitter.emit(document.get("name"), document);
}
}
}
};
view.setMap(map, null);
}
Query query = view.createQuery();
return query;
}
Note that the view will only exclude key ignoreUserId you passed to it during the first call, and will ignore all the others during next calls (because it will create view only once during the first call)
So you need to create new view for every key they want to omit. But if you have a lot of keys you want to exclude or does it often, it would be inefficient and boilerplate.
Do you know any better solution or hack ?
Any help appreciated
Thanks in advance
Upvotes: 5
Views: 3106
Reputation: 3947
CouchBase is not designed for the types of queries you want to issue here. It is designed to use map/reduce under the hood to identify specific documents with a range (down to a range of 1 document), not exclude specific documents. What you are asking is not going to be efficient in CouchBase. You are using the wrong technology if your goal is to do these kinds of queries efficiently.
If your hands are tied and you are locked into CouchBase Lite, though, you have to work within the types of queries you have. Excluding a particular value can be restated as including all other values. If you want to do that in CouchBase, you use range queries with ranges designed to not include the value you want to exclude.
Here is a brief conceptual example. Suppose your view has documents with keys of "A", "B", "C", "D", "F", and "X" and you want to issue a query whose result excludes document "D". You could get the result you desired by first issue a range query for "A"-"C" and then issuing a second range query for "E"-"Z". The two results combined would be everything excluding "D".
Of course, those are simple keys. The more complex your keys, the more complex your range endpoints become to exclude specific values. The more keys you want to exclude, the more queries you have to perform (you have to perform N + 1 queries for N excluded terms). You are probably going to have a more efficient system by querying for all values in the view and filtering them in code yourself.
Upvotes: 5