docs: function(json, parent, options) {
  	parent = json.timeSeries ? parent ||  _.first( _.keys( json ) ) : parent;
  	
  	// make a smaller object if there are selections
  	if (options && options.series && options.series.length) {
  		json = selectChildren(json, parent, options.series);
  	}
  		
  	// select columns and sort 
  	var columns = parent 
  		? _.plain(json).pselect(parent).sortPlain(parent).keys().value() 
  		: _.plain(json).sortPlain(parent).keys().value()
  	, series_list = (json.timeSeries && json.series_list) || (parent && json[parent] 
  		? _.plain(json).query('select *, pivot').sortPlain(parent).keys().value()
  		: (!(parent) && _.keys( sortPlain(json) ))) || []
  		
  	// pivot so that the related_facets become the rows;
  	, rows = _.plain(json.timeSeries ? _.pick(json, parent) : json).query('select *, pivot')
  	, objects = _.clean({
  		values: undefined,
  		facet: json.timeSeries ? undefined : parent,
  		date_key: json.timeSeries ? json.date_key : undefined,
  		interval: json.timeSeries ? json.interval : undefined,
  		series_list: series_list,
  		spage: 0,
  		spageSize: Math.min(columns.length, _.coerce('number', (options && options.maxSeries) || 0) || 50),
  		depth: depth(json),
  		timeSeries: json.timeSeries ? true : undefined,
  		multiSeries: json.timeSeries ? undefined : true
  	}, options);
  	
  	// use this object as a hash lookup: {row_key1: {v1: 3, v2: 4 ...}, row_key2: {}}
  	// loop over the sorted (rows) and for each series item (column) make an entry	
  	objects.series_length = objects.series.length;
  	objects.values = _mapSeries( rows.value(), rows.sortPlain(parent).keys().value(), columns, json.timeSeries);	
  	return objects;
  	
  	
  	// now slice out only the series being selected, either by series: [] or using spage / spageSize
  	// Note: decode items in the incoming options.series.
  	if (options && options.series && options.series.length) {
  		
  		// if options.series has been encoded, must decode it first
  		columns = _.intersection(_.map(options.series, function(s) { return decodeURIComponent(s); }), columns);				
  	} else {
  		objects.series = columns;
  	}
  	
  	if (options && options.hasOwnProperty('spage') && options.spageSize) {
  		columns = objects.series = columns.slice((objects.spage * objects.spageSize),
  				((objects.spage * objects.spageSize) + objects.spageSize));	
  	}
  	
  	// use this object as a hash lookup: {row_key1: {v1: 3, v2: 4 ...}, row_key2: {}}
  	// loop over the sorted (rows) and for each series item (column) make an entry	
  	objects.series_length = objects.series.length;
  	objects.values = _mapSeries( rows.value(), rows.sortPlain(parent).keys().value(), columns, json.timeSeries);
  	return objects;
  }