Dynamic views with dynamic sorting

27 views
Skip to first unread message

Brendan Duddridge

unread,
Jun 11, 2015, 11:45:46 PM6/11/15
to mobile-c...@googlegroups.com
Hi,

I'm struggling a bit here trying to figure out a way to generate dynamic views for map/reduce.

I have an entity called TFRecord that contains record details. Each instance of TFRecordDetails can have a different schema depending on the TFForm and set of TFFields defined.

I've created my view like this on my TFForm model entity:

NSString *viewName = [NSString stringWithFormat:@"records-%@", self.document.documentID];
CBLView *recordsView = [self.database viewNamed:viewName];


So as you can see the name of the records view is generated from the document ID of the TFForm entity.

These records need to be sorted by multiple levels of sorting criteria. I've got these keys that I'd like to use to reference the values from the TFRecord document for sorting purposes. They can be first sorted by a grouping field, then a first sort field, second sort field, and third sort field as defined on the TFForm class.


NSString *groupFieldKey = [self.groupField valueKeyName];
NSString *sortField1Key = [self.sortField1 valueKeyName];
NSString *sortField2Key = [self.sortField2 valueKeyName];
NSString *sortField3Key = [self.sortField3 valueKeyName];


So somehow I need to be able to generate a map/reduce function that will extract the values from the TFRecord entity based on the keys from the above vars. But according to the documentation, the map/reduce functions must be pure and not reference any external state information, only referencing values from the document JSON itself.

Does that means it's not possible to generate a view from a dynamically generated set of keys?


This is what one record looks like in my model:


{
 
"alertCount": "0",
 
"dateCreated": "2014-09-29 05:44:32 +0000",
 
"dateModified": "2014-09-29 05:44:51 +0000",
 
"formId": "form-11770309-9278-445D-A0E5-FF9B05D2552E",
 
"hasAlarm": "0",
 
"isFavourite": "0",
 
"linkFromField": "field-008C209D-A199-423C-8027-3813AA848F84",
 
"linkFromRecord": "rec-1E774FB1-A419-48AC-ACA5-5A8A7EC0D5A5",
 
"primaryKey": "3E3E0DA3-3809-4A13-8B81-353404C970FB",
 
"sortOrder": "0",
 
"type": "TFFormEntry",
 
"values": {
     
"field-2AE29531-6B5F-4D45-9625-C9D43520778A-note": "Deployment of updated Tap Forms version under way.",
     
"field-608BE174-A17F-46F7-88A7-D02F3E7D2B01-date_time": "2014-09-29 05:44:40 +0000",
     
"field-C6572946-36E0-4ED9-BF02-A01F4D787FE6-text": "Deploy Tap Forms"
 
}
}


One or more of the groupFieldKey, sortField1Key, sortField2Key, or sortField3Key may be in the set of values in the document. "values" is a dictionary on my TFRecord model object where I'm storing all the values for a record, keyed by the field's ID. 

So basically I don't know what to put into the map block to achieve what I need. I also need to be able to query these objects in a number of different ways. But I'll get to that once I can figure out how to get my records sorted. The user may even have a different set of fields displayed in the list than what they are sorting on.


I tried building a function that was referencing those keys above, but that obviously doesn't work.


Any ideas?


I just don't know what to emit here:


if (!recordsView.mapBlock) {
   
[recordsView setMapBlock: MAPBLOCK({
       
if ([doc[@"type"] isEqualToString:@"TFRecord"]) {

         
// what do I put here to be able to extract out the values
         
// for the dynamically generated groupFieldKey, sortField1Key,
         
// sortField2Key, and sortField3Key?
         
         
NSDictionary *values = doc[@"values"];
         
// need to get the value for the dynamic keys from the
         
// values dictionary then emit that value.

          emit
(@[doc[groupField1Key], doc[sortField1Key], doc[sortField2Key], doc[sortField3Key]], doc);
                }
   
}) reduceBlock:^id(NSArray *keys, NSArray *values, BOOL rereduce) {
       
return @(values.count);
   
} version: @"1"];
}


The above is obviously not pure because it references the local "Key" variables within the map function.

So I'm stuck.

Thanks,

Brendan

Brendan Duddridge

unread,
Jun 11, 2015, 11:52:20 PM6/11/15
to mobile-c...@googlegroups.com
I guess I'm butting up against this rule here from the documentation:

  • Don't try to "parameterize" the map function by referring to an external variable whose value you change when querying. It won't work. People sometimes try this because they want to find various subsets of the data, like all the items of a particular color. Instead, emit all the values of that property, and use a key range in the query to pick out the rows with the specific value you want.
The problem is the values within my above "values" dictionary will be different from record to record. They'll have a different set of fields from one record to the next even. 

Jens Alfke

unread,
Jun 12, 2015, 12:20:33 PM6/12/15
to mobile-c...@googlegroups.com

On Jun 11, 2015, at 8:45 PM, Brendan Duddridge <bren...@gmail.com> wrote:

So somehow I need to be able to generate a map/reduce function that will extract the values from the TFRecord entity based on the keys from the above vars. But according to the documentation, the map/reduce functions must be pure and not reference any external state information, only referencing values from the document JSON itself.

It can’t reference any variable external state. If the view definition uses an external value, but that value never changes, that’s fine. The exact requirement is that, given the same input document, the map function must always emit the same output.

It sounds like it’s fine for the view to reference values from the TFRecord. You can fetch those values into local variables, then define the view and use those variables. The block will adopt and hold onto those values. What you’ll need to do, though, is notice when the TFRecord changes and update the view’s map function and version string (which will rebuild the index.)

—Jens
Reply all
Reply to author
Forward
0 new messages