function select($fields = NULL, $filter = NULL, array $options = NULL, $ttl = 0)
{
if (!$options) {
$options = [];
}
$options += ['group' => NULL, 'order' => NULL, 'limit' => 0, 'offset' => 0];
$fw = \Base::instance();
$cache = \Cache::instance();
if (!($cached = $cache->exists($hash = $fw->hash($this->db->dsn() . $fw->stringify([$fields, $filter, $options])) . '.mongo', $result)) || !$ttl || $cached[0] + $ttl < microtime(TRUE)) {
if ($options['group']) {
$grp = $this->collection->group($options['group']['keys'], $options['group']['initial'], $options['group']['reduce'], ['condition' => $filter, 'finalize' => $options['group']['finalize']]);
$tmp = $this->db->selectcollection($fw->get('HOST') . '.' . $fw->get('BASE') . '.' . uniqid(NULL, TRUE) . '.tmp');
$tmp->batchinsert($grp['retval'], ['w' => 1]);
$filter = [];
$collection = $tmp;
} else {
$filter = $filter ?: [];
$collection = $this->collection;
}
$this->cursor = $collection->find($filter, $fields ?: []);
if ($options['order']) {
$this->cursor = $this->cursor->sort($options['order']);
}
if ($options['limit']) {
$this->cursor = $this->cursor->limit($options['limit']);
}
if ($options['offset']) {
$this->cursor = $this->cursor->skip($options['offset']);
}
$result = [];
while ($this->cursor->hasnext()) {
$result[] = $this->cursor->getnext();
}
if ($options['group']) {
$tmp->drop();
}
if ($fw->get('CACHE') && $ttl) {
// Save to cache backend
$cache->set($hash, $result, $ttl);
}
}
$out = [];
foreach ($result as $doc) {
$out[] = $this->factory($doc);
}
return $out;
}