/**
  * Read Data
  *
  * @param Model $model Model Instance
  * @param array $query Query data
  * @return array Results
  * @access public
  */
 public function read(&$model, $query = array())
 {
     $query = $this->_setEmptyArrayIfEmpty($query);
     extract($query);
     if (!empty($order[0])) {
         $order = array_shift($order);
     }
     if (!empty($conditions['_id']) && !is_object($conditions['_id'])) {
         $conditions['_id'] = new MongoId($conditions['_id']);
     }
     $fields = is_array($fields) ? $fields : array($fields);
     $conditions = is_array($conditions) ? $conditions : array($conditions);
     $order = is_array($order) ? $order : array($order);
     /*
      * before update, model::save() check exist record with conditions key (ex: Post._id).
      * Convert Post._id to _id and make a MongoId object
      */
     if (!empty($conditions[$model->alias . '._id'])) {
         $conditions['_id'] = new MongoId($conditions[$model->alias . '._id']);
         unset($conditions[$model->alias . '._id']);
     }
     $result = $this->_db->selectCollection($model->table)->find($conditions, $fields)->sort($order)->limit($limit)->skip(($page - 1) * $limit);
     if ($model->findQueryType === 'count') {
         return array(array($model->alias => array('count' => $result->count())));
     }
     $results = null;
     while ($result->hasNext()) {
         $mongodata = $result->getNext();
         if ($this->config['set_string_id'] && !empty($mongodata['_id']) && is_object($mongodata['_id'])) {
             $mongodata['_id'] = $mongodata['_id']->__toString();
         }
         $results[][$model->alias] = $mongodata;
     }
     return $results;
 }
 /**
  * getMapReduceResults
  *
  * @param mixed $query
  * @return void
  * @access public
  */
 public function getMapReduceResults($query)
 {
     $result = $this->query($query);
     if ($result['ok']) {
         $data = $this->_db->selectCollection($result['result'])->find();
         return $data;
     }
     return false;
 }
    /**
     * mapReduce
     *
     * @param mixed $query
     * @param integer $timeout (milli second)
     * @return mixed false or array
     * @access public
     */
    public function mapReduce($query, $timeout = null) {

        //above MongoDB1.8, query must object.
        if (isset($query['query']) && !is_object($query['query'])) {
            $query['query'] = (object) $query['query'];
        }
        
        $result = $this->query($query);
        if ($result['ok']) {
            $data = $this->_db->selectCollection($result['result'])->find();
            if (!empty($timeout)) {
                $data->timeout($timeout);
            }
            return $data;
        }
        return false;
    }
 /**
  * Read Data
  *
  * @param Model $model Model Instance
  * @param array $query Query data
  * @return array Results
  * @access public
  */
 public function read(&$model, $query = array())
 {
     $query = $this->_setEmptyArrayIfEmpty($query);
     extract($query);
     if (!empty($order[0])) {
         $order = array_shift($order);
     }
     $result = $this->_db->selectCollection($model->table)->find($conditions, $fields)->sort($order)->limit($limit)->skip(($page - 1) * $limit);
     if ($model->findQueryType === 'count') {
         return array(array($model->name => array('count' => $result->count())));
     }
     $results = null;
     while ($result->hasNext()) {
         $mongodata = $result->getNext();
         if (empty($mongodata['id'])) {
             $mongodata['id'] = $mongodata['_id']->__toString();
         }
         $results[] = $mongodata;
     }
     return $results;
 }
/**
 * Read Data
 *
 * For deleteAll(true) calls - the conditions will arrive here as true - account for that and switch to an empty array
 *
 * @param Model $Model Model Instance
 * @param array $query Query data
 * @return array Results
 * @access public
 */
	public function read(&$Model, $query = array()) {
		if (!$this->isConnected()) {
			return false;
		}

		$this->_setEmptyValues($query);
		extract($query);

		if (!empty($order[0])) {
			$order = array_shift($order);
		}
		$this->_stripAlias($conditions, $Model->alias);
		$this->_stripAlias($fields, $Model->alias, false, 'value');
		$this->_stripAlias($order, $Model->alias, false, 'both');

		if (!empty($conditions['_id'])) {
			$this->_convertId($conditions['_id']);
		}

		$fields = (is_array($fields)) ? $fields : array($fields => 1);
		if ($conditions === true) {
			$conditions = array();
		} elseif (!is_array($conditions)) {
			$conditions = array($conditions);
		}
		$order = (is_array($order)) ? $order : array($order);

		if (is_array($order)) {
			foreach($order as $field => &$dir) {
				if (is_numeric($field) || is_null($dir)) {
					unset ($order[$field]);
					continue;
				}
				if ($dir && strtoupper($dir) === 'ASC') {
					$dir = 1;
					continue;
				} elseif (!$dir || strtoupper($dir) === 'DESC') {
					$dir = -1;
					continue;
				}
				$dir = (int)$dir;
			}
		}

		if (empty($offset) && $page && $limit) {
			$offset = ($page - 1) * $limit;
		}

		$return = array();

		$this->_prepareLogQuery($Model); // just sets a timer
		if (empty($modify)) {
			if ($Model->findQueryType === 'count' && $fields == array('count' => true)) {
				$count = $this->_db
					->selectCollection($Model->table)
					->count($conditions);
				if ($this->fullDebug) {
					$this->logQuery("db.{$Model->useTable}.count( :conditions )",
						compact('conditions', 'count')
					);
				}
				return array(array($Model->alias => array('count' => $count)));
			}

			$return = $this->_db
				->selectCollection($Model->table)
				->find($conditions, $fields)
				->sort($order)
				->limit($limit)
				->skip($offset);
			if ($this->fullDebug) {
				$count = $return->count();
				$this->logQuery("db.{$Model->useTable}.find( :conditions, :fields ).sort( :order ).limit( :limit ).skip( :offset )",
					compact('conditions', 'fields', 'order', 'limit', 'offset', 'count')
				);
			}
		} else {
			$options = array_filter(array(
				'findandmodify' => $Model->table,
				'query' => $conditions,
				'sort' => $order,
				'remove' => !empty($remove),
				'update' => array('$set' => $modify),
				'new' => !empty($new),
				'fields' => $fields,
				'upsert' => !empty($upsert)
			));
			$return = $this->_db
				->command($options);
			if ($this->fullDebug) {
				if ($return['ok']) {
					$count = 1;
					if ($this->config['set_string_id'] && !empty($return['value']['_id']) && is_object($return['value']['_id'])) {
						$return['value']['_id'] = $return['value']['_id']->__toString();
					}
					$return[][$Model->alias] = $return['value'];
				} else {
					$count = 0;
				}
				$this->logQuery("db.runCommand( :options )",
					array('options' => array_filter($options), 'count' => $count)
				);
			}
		}

		if ($Model->findQueryType === 'count') {
			return array(array($Model->alias => array('count' => $return->count())));
		}

		if (is_object($return)) {
			$_return = array();
			while ($return->hasNext()) {
				$mongodata = $return->getNext();
				if ($this->config['set_string_id'] && !empty($mongodata['_id']) && is_object($mongodata['_id'])) {
					$mongodata['_id'] = $mongodata['_id']->__toString();
				}
				$_return[][$Model->alias] = $mongodata;
			}
			return $_return;
		}
		return $return;
	}
 /**
  * Read Data
  *
  * For deleteAll(true) calls - the conditions will arrive here as true - account for that and switch to an empty array
  *
  * @param Model $Model Model Instance
  * @param array $query Query data
  * @return array Results
  * @access public
  */
 public function read(&$Model, $query = array())
 {
     if (!$this->isConnected()) {
         return false;
     }
     $this->_setEmptyValues($query);
     extract($query);
     if (!empty($order[0])) {
         $order = array_shift($order);
     }
     $this->_stripAlias($conditions, $Model->alias);
     $this->_stripAlias($fields, $Model->alias, false, 'value');
     $this->_stripAlias($order, $Model->alias, false, 'both');
     if (!empty($conditions['_id'])) {
         $this->_convertId($conditions['_id']);
     }
     $fields = is_array($fields) ? $fields : array($fields => 1);
     if ($conditions === true) {
         $conditions = array();
     } elseif (!is_array($conditions)) {
         $conditions = array($conditions);
     }
     $order = is_array($order) ? $order : array($order);
     if (is_array($order)) {
         foreach ($order as $field => &$dir) {
             if (is_numeric($field) || is_null($dir)) {
                 unset($order[$field]);
                 continue;
             }
             if ($dir && strtoupper($dir) === 'ASC') {
                 $dir = 1;
                 continue;
             } elseif (!$dir || strtoupper($dir) === 'DESC') {
                 $dir = -1;
                 continue;
             }
             $dir = (int) $dir;
         }
     }
     if (empty($offset) && $page && $limit) {
         $offset = ($page - 1) * $limit;
     }
     $return = array();
     $this->_prepareLogQuery($Model);
     // just sets a timer
     if (empty($modify)) {
         if ($Model->findQueryType === 'count' && $fields == array('count' => true)) {
             $count = $this->_db->selectCollection($Model->table)->count($conditions);
             if ($this->fullDebug) {
                 $this->logQuery("db.{$Model->useTable}.count( :conditions )", compact('conditions', 'count'));
             }
             return array(array($Model->alias => array('count' => $count)));
         }
         $return = $this->_db->selectCollection($Model->table)->find($conditions, $fields)->sort($order)->limit($limit)->skip($offset);
         if ($this->fullDebug) {
             $count = $return->count();
             $this->logQuery("db.{$Model->useTable}.find( :conditions, :fields ).sort( :order ).limit( :limit ).skip( :offset )", compact('conditions', 'fields', 'order', 'limit', 'offset', 'count'));
         }
     } else {
         $options = array_filter(array('findandmodify' => $Model->table, 'query' => $conditions, 'sort' => $order, 'remove' => !empty($remove), 'update' => array('$set' => $modify), 'new' => !empty($new), 'fields' => $fields, 'upsert' => !empty($upsert)));
         $return = $this->_db->command($options);
         if ($this->fullDebug) {
             if ($return['ok']) {
                 $count = 1;
                 if ($this->config['set_string_id'] && !empty($return['value']['_id']) && is_object($return['value']['_id'])) {
                     $return['value']['_id'] = $return['value']['_id']->__toString();
                 }
                 $return[][$Model->alias] = $return['value'];
             } else {
                 $count = 0;
             }
             $this->logQuery("db.runCommand( :options )", array('options' => array_filter($options), 'count' => $count));
         }
     }
     if ($Model->findQueryType === 'count') {
         return array(array($Model->alias => array('count' => $return->count())));
     }
     if (is_object($return)) {
         $_return = array();
         while ($return->hasNext()) {
             $mongodata = $return->getNext();
             if ($this->config['set_string_id'] && !empty($mongodata['_id']) && is_object($mongodata['_id'])) {
                 $mongodata['_id'] = $mongodata['_id']->__toString();
             }
             $_return[][$Model->alias] = $mongodata;
         }
         // gestion des relations
         if ($Model->recursive > -1) {
             foreach ($Model->__associations as $type) {
                 foreach ($Model->{$type} as $assoc => $assocData) {
                     $linkModel =& $Model->{$assoc};
                     $linkModel->recursive = -1;
                     $db =& ConnectionManager::getDataSource($linkModel->useDbConfig);
                     switch ($type) {
                         case 'hasMany':
                             //$ids = Set::classicExtract($_return, '{n}.'.$Model->alias.'._id');
                             $ids = $this->_getNonEmptyIds($_return, $Model->alias, $Model->primaryKey);
                             $_return = $this->_getManySubElements($_return, $ids, $Model, $linkModel, $assoc, $assocData);
                             break;
                         case 'belongsTo':
                             $ids = $this->_getNonEmptyIds($_return, $Model->alias, $assocData['foreignKey']);
                             $_return = $this->_getBelongsToSubElement($_return, $ids, $Model, $linkModel, $assoc, $assocData);
                             break;
                         case 'hasOne':
                             $ids = $this->_getNonEmptyIds($_return, $Model->alias, $Model->primaryKey);
                             $_return = $this->_getOneSubElement($_return, $ids, $Model, $linkModel, $assoc, $assocData);
                             break;
                         case 'hasList':
                             $ids = $this->_getLists($_return, $Model->alias, $assocData['listName']);
                             $_return = $this->_getListSubElements($_return, $ids, $Model, $linkModel, $assoc, $assocData);
                             /*
                             								$ids = Set::classicExtract($_return, '{n}.'.$Model->alias.'.'.$assocData['foreignKey']);
                             								//$ids = $this->_getNonEmptyIds($_return, $Model->alias, $assocData['foreignKey']);
                             								$subResult = array();
                             								if(!empty($ids)) {
                             									$subResult = $linkModel->find('all', array('conditions' => array($assocData['foreignKey'] => array('$in' => $ids))));
                             									$subResult = Set::combine($subResult, '{n}.'.$linkModel->alias.'._id', '{n}');
                             								}
                             								foreach ($_return as &$element) {
                             									if(
                             										!empty($element[$Model->alias][$assocData['foreignKey']]) AND
                             										!empty($subResult[$element[$Model->alias][$assocData['foreignKey']]])
                             									) {
                             										$element[$assoc] = $subResult[$element[$Model->alias][$assocData['foreignKey']]][$assoc];
                             									} else {
                             										$element[$assoc] = array();
                             									}
                             								}
                             								//*/
                             break;
                     }
                     if (isset($db) && method_exists($db, 'queryAssociation')) {
                         $stack = array($assoc);
                         //$db->queryAssociation($Model, $linkModel, $type, $assoc, $assocData, $array, true, $_return, $Model->recursive - 1, $stack);
                         //unset($db);
                         if ($type === 'hasMany') {
                             $filtered[] = $assoc;
                         }
                     }
                 }
             }
             if (!isset($filtered)) {
                 $filtered = array();
             }
             $this->__filterResults($_return, $Model, $filtered);
         }
         return $_return;
     }
     return $return;
 }