Sorry, you can’t do that. The map function runs while the view is being indexed, before the query. And multiple queries will use the same index. That’s why the map function has to be a pure function with no external state and no side effects.
So when you design the map function you have to think of handling all queries, not a specific query. In your case you want to put all three keys into the index so they can be searched for. The way to implement this is to make the map function emit all three of the keys —
Then set the query’s keys property to an array [localkey1, localkey2, localkey3]. That will find all docs with any of those local key strings. You may get duplicate rows in the result if one of the documents contains more than one of the local keys; you’ll have to filter those out yourself.
Thank you for these explanations.
I managed to emit my document this way, and i adapted my code.
I have a “code design” question for you, if you can help…
If one of my local variable change (localKey1 for example), is it okay to reinitialize query entirely ?
By recalling my method below " initializeQuery() ".
At the moment i call my query like that :
protected static void initializeQuery() {
liveQuery = getQuery(database, mood1, mood2, mood3).toLiveQuery();
liveQuery.addChangeListener(new LiveQuery.ChangeListener() {
@Override
public void changed(LiveQuery.ChangeEvent event) {
if (event.getSource().equals(liveQuery)) {
QueryEnumerator result = event.getRows();
for (Iterator<QueryRow> it = result; it != null && it.hasNext(); ) {
QueryRow row = it.next();
.......
.......
....... **********HERE i do my "filtering of result""**************
My getQuery method is
public static Query getQuery(Database database, String localKey1, String localKey2, String localKey3) {
/* --------------- CREATE A VIEW --------------*/
final com.couchbase.lite.View view = database.getView("matchView");
if (view.getMap() == null) {
final Mapper map = new Mapper() {
@Override
public void map(Map<String, Object> document, Emitter emitter) {
if((boolean) document.get("isOnline"))
{
if (!(boolean) document.get("isEnabled"))
{
if ((document.get("numberOfKey")).equals("3"))
{
emitter.emit(document.get("key1"), document.get("userId")) ;
emitter.emit(document.get("key2"), document.get("userId")) ;
emitter.emit(document.get("key3"), document.get("userId")) ;
}
else if ((document.get("numberOfKey")).equals("2"))
{
emitter.emit(document.get("key1"), document.get("userId")) ;
emitter.emit(document.get("key2"), document.get("userId")) ;
}
else if ((document.get("numberOfKey")).equals("1"))
{
emitter.emit(document.get("key3"), document.get("userId")) ;
}
}
}
}
};
view.setMap(map, "1");
}
/* ---------------CREATE the Query Object --------------*/
Query query = view.createQuery();
query.setDescending(true);
java.util.List<Object> keys = new ArrayList<Object>();
keys.add(key1);
keys.add(key2);
keys.add(key3);
query.setKeys(keys);
return query;
}
So is my code correct ? Particulary about using static methods and compare string in the view ?
You can have as many LiveQueries as you want, although it’ll eventually slow down the app because each one will keep re-running the query after the database changes. For efficiency it’s best to have them running only when you’re actively using their results, like when a table view driven by one is being displayed.
I’m not an Android programmer so I don’t know anything about fragments or activities. Maybe @hideki can answer this.
In fact on 4 documents containing the Keys i give to my query, it returns me only 2 document…
Even when restarting the livequery these 2 docs are still not there.
Any idea on this kind of issue ? (I checked in my bucket, and Keys are present in the doc).
Where would you advice me to filter results to avoid duplicates so ?
Well, you’d iterate over the returned query rows and skip the ones that are from the same document.
Is there no way to do track duplicates inside my database View or inside my Query ?
You can use grouping to merge duplicate keys, but what you’re getting are multiple keys emitted from the same document. There’s no automatic mechanism to merge those.
I don’t understand what you’re asking for … You’re already detecting the duplicates in the code you showed above. (Although using an ArrayList is going to be really inefficient! Use a HashMap instead.)
Basically wherever you’re iterating the results to do whatever you need to do, check for duplicates that way and skip them.
for (bookID in doc.books) {
book = doc.books[bookID]
emit(book.genre, null)
}
Now you have an index of the genres of all books. If you want to get a list of genres, set the groupLevel of the query to 1 so it will aggregate all the identical genre keys together.