Search code examples
javaandroidcouchbasecouchbase-litecouchbase-view

Querying Couchbase Lite problems using MapReduce Views


I have been struggling with a problem related to querying Couchbase lite 1.4 database on my mobile Android device. It seems for me that I don't fully understand how querying using MapReduce Views works like.

So I have the following setup:

1) Database that contains entities like so:

{
  dateCreated: 1220227200,
  relatedObjectId: "objectId_23445"
  type: "mytype"
}

2) I would like to query my database and get all objects of type "mytype", which are related to object with a given id (relatedObjectId field) and sorted by dateCreated field.

Here is my map function which generates a view:

public void map(Map<String, Object> document, Emitter emitter) {
    if (document.get("type") != null && document.get("type").equals("mytype")) {
        List<Object> keys = new ArrayList<Object>();
        keys.add(document.get("dateCreated");
        keys.add(document.get("relatedObjectId"));
        emitter.emit(keys, null);
    }
}

3) This function produces results like so:

[1220227200, objectId_23445],
[1220227201, objectId_3],
[1220227202, objectId_7],
[1220227203, objectId_8],
[1220227204, objectId_23445]

4) I want to get all objects with an id "objectId_23445" sorted by date like so:

[1220227200, objectId_23445],   
[1220227204, objectId_23445]

5) But as a result I always get all objects from a database.

First dateCreated seems to be taken into account but my second part of a key (relatedObjectId) does not really takes part in filtering. So I always get a list from point 3.

My query looks like so:

String relatedObjectId = "objectId_23445"
Query query = CouchbaseViews.GetAllMyTypeItems().createQuery();            
query.setDescending(true);

ArrayList<Object> startKey = new ArrayList<Object>();
startKey.add(0);
startKey.add(relatedObjectId);

ArrayList<Object> endKey = new ArrayList<Object>();
endKey.add(Calendar.getInstance().getTimeInMillis());
endKey.add(relatedObjectId);

query.setStartKey(endKey);
query.setEndKey(startKey);

So I need help with this. In my opinion I just don't understand how to filter objects when key is a compound key (arrayList in my case).

Ofc as a workaround I can only emit relatedObjectId and then sort data manually but is this a correct way to do so?

Any help will be appreciated, thanks in advance!


Solution

  • I solved my problem after some additional research (including some posts on stackoverflow).

    It seems like in order to achieve what i wanted first of all i have to reverse an order in map() function:

    public void map(Map<String, Object> document, Emitter emitter) {
        if (document.get("type") != null && document.get("type").equals("mytype")) {
            List<Object> keys = new ArrayList<Object>();    
            //order of elements have been changed                        
            keys.add(document.get("relatedObjectId"));
            keys.add(document.get("dateCreated");
            emitter.emit(keys, null);
        }
    }
    

    After this modification our map() function produces followig output:

    [objectId_23445, 1220227200],
    [objectId_3, 1220227201],
    [objectId_7, 1220227202],
    [objectId_8, 1220227203],
    [objectId_23445, 1220227204]
    

    And finally i have to modify my query like so:

    String relatedObjectId = "objectId_23445"
    Query query = CouchbaseViews.GetAllMyTypeItems().createQuery();            
    query.setDescending(true);
    
    ArrayList<Object> startKey = new ArrayList<Object>();            
    startKey.add(relatedObjectId);
    
    ArrayList<Object> endKey = new ArrayList<Object>();
    endKey.add(relatedObjectId);
    endKey.add(new HashMap<>());
    
    query.setStartKey(endKey);
    query.setEndKey(startKey);
    

    Now my query will select all elements with a relatedObjectId first and then sort this sequence and since we will always have the same prefix for all elements (relatedObjectId), second item will be taken into account during sorting (dateCreated).