Quering view with keys array?


#1

Hi there!

I have a view which emits keys like this [id, since, …], where “id” is a string type, and “since” is a long type.
Can I query this view to get documents from set of ids? E.g. I want to get only docs with id=“1” and id=“2”.
Tried to set startKey and endKey, or simple setKeys with list of ids but no luck:


List keys = new ArrayList<>();
List ids = new ArrayList<>();
ids.add(“1”);
ids.add(“2”);
keys.add(ids);
query.setKeys(keys);


#2

Please make it a habit of including the version you are using now that there are two supported major versions out there. This one looks like 1.4 though. The answer to your question depends entirely on how you set up your view. What does your view definition look like?


#3

@borrrden
Sorry, I thought it was quite clear that I am using 1.x version :slight_smile:

  1. Yes, CBL 1.4, Android, Java

  2. For the sake of simplicity View setup look like this:

         private View registerView(String name, final String docType, final String[] docKeys, String fieldName) {
         View view = mDatabase.getView(name);
         view.setMap(new Mapper() {
    
             @Override
             public void map(Map<String, Object> document, Emitter emitter) {
    
                 if(document.get("doc_type").equals(docType)) {
    
                     // Create keys to emit.
                     List<Object> emitKeys = new ArrayList<>();
                     for (String key : docKeys)
                         emitKeys.add(document.get(key));
    
                     // Emit keys to mapper.
                     emitter.emit(emitKeys, document.get(fieldName));
                 }
             }
         }, "1");
    
         return view;
         }
    
  3. Create view:

         View testView = registerView("test", new String[] {"some_id","since"}, "value");
    
  4. Doc’s field “some_id” is a string id value of another document, “since” is a value of long type.

  5. Try to query this view by the 1st key only:

        // Create query keys.
        List<Object> keys = new ArrayList<>();
        List<Object> docs = new ArrayList<>();
        docs.add("id1");
        docs.add("id2");
        keys.add(docs);
    
        // Create and run query.
        Query query = testView.createQuery();
        query.setKeys(keys);
        //query.setDescending(true);
        //query.setGroupLevel(1);
        //query.setMapOnly(true);
        QueryEnumerator rows = query.run();

#4

The first thing I notice is your call to registerView and its definition don’t seem to match up though (the registerView definition has four arguments, but the call only has three?).

The map function has to be a pure function, meaning that for a given document, it will always produce the same output. This is not the case in your as it varies by docType, docKeys and fieldName. That means if any of these changes then you just invalidated your view and unless you changed the version number and triggered a reindex, your index data is corrupt. Moving past that, it looks like you want to emit the values for a few keys into your view. That means that your keys are now compound keys, and they will not match “id1” and “id2” anymore. They will be [“id1”, something] and [“id2”, something]. You can’t set a partial key match. If you need to lookup by key, you need to set up your view in such a way that the key matches exactly what you want. Or falls into a range (for startKey and endKey). In this example a startKey of [“id1”] and an endKey of [“id2”, {}] will contain both of those entries (and possibly other ones).


#5

Yep, I missed one arg :slight_smile:
(though this does not matter, this is not a real code)

Anyway, I have a strange feelings that here on forum I saw an answer from someone who told that even compound keys can be queried in such manner.

Thanks for clarification!


#6

They may have been referring to key ranges, which can make use of compound keys. As for the keys property itself, it is just a simple list of keys that you want to pull from the view as is.