0

How does one query a couchbase view that contains two keys; the first an NSNumber type (called created in the example below) and an NSString type (called username).

CBLView* view = [database viewNamed:@"by_username"];
if (!view.mapBlock)
{
    [view setMapBlock: MAPBLOCK({
        if ( [doc[@"type"] isEqualToString:@"user"] )
        {
            emit(@[doc[@"created"],doc[@"username"]], nil);
        };
    }) version: @"2"];
}

CBLQuery* q = [view createQuery];
q.keys = @[ @[ @{}, @"john" ] ];
// run query

With the query above, I'm expecting to have all documents with a doc[@"username"] == @"john" matched, regardless of the value of doc[@"created"] (i.e. I'm assuming @{} is the equivalent of a wildcard).

However, the query returns 0 matches despite the presence of many documents with username @"john". I must be doing something wrong so any insight is greatly appreciated!

theMayer
  • 15,456
  • 7
  • 58
  • 90
John Dunne
  • 387
  • 1
  • 6
  • 12

2 Answers2

1

It appears that you are trying to search backwards, your index should be organized by the first item you want to search by. So, if you don't care about created, you should remove it from the index, because it results in the issue you have here. Understanding that you may need this for some other query, create a new view with this change.

Also, as a general note on your answer, it does absolutely no good to emit the whole doc in an index. It results in doubling the size of storage along with inefficient operation of the view framework.

theMayer
  • 15,456
  • 7
  • 58
  • 90
  • With your input @theMayer my code now becomes emit(doc[@"username"], doc[@"created"]); and I'm then able to sort against just @"value" instead of @"value.created". – John Dunne Jan 25 '15 at 20:32
  • @JohnDunne - what is your search case? It appears you are searching by `created` then by `username` or vice-versa, so one of the two cases ought to get you what you want. I am confused if not - please clarify. – theMayer Jan 26 '15 at 04:21
  • I'm attempting to search by `username` and sort by `created`. I've now achieved with your input what I wanted, by having `username` in the index and leaving the sorting by `created` to an `NSSortDescriptor` instance. My original understanding of only being able to sort a query result by the key was incorrect. – John Dunne Jan 28 '15 at 09:02
0

Further investigation presented the possibility of using NSSortDescriptior's when querying a database, which simplified my code to the following:

CBLView* view = [database viewNamed:@"by_username"];
if (!view.mapBlock)
{
    [view setMapBlock: MAPBLOCK({
        if ( [doc[@"type"] isEqualToString:@"user"] )
        {
            emit(doc[@"username"], doc[@"created"]);
        };
    }) version: @"2"];
}

CBLQuery* q = [view createQuery];
q.keys = @[ @"john" ];

q.sortDescriptors = @[ [[NSSortDescriptor alloc] initWithKey:@"value" ascending:NO] ];

where sortDescriptors is an array with just a single NSSortDescriptor in this case. Notice that the mapBlock now emits a 'doc' object and so this appears in the NSSortDescriptor as the 'value' key path and so 'created' is the available to be sorted against. Hopefully this will help others.

John Dunne
  • 387
  • 1
  • 6
  • 12