2
votes

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!

1

1 Answers

2
votes

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).