* @return \loyalsoft\MongoQueryOptionBuilder */ public static function QueryOptionBuilder() { return new MongoQueryOptionBuilder(); } /** * * @param type $connStr * @return \MongoDB\Driver\Manager|false */ public function conn($connStr, $dbPrefix = "") { try { $this->mc = new \MongoDB\Driver\Manager($connStr); $this->dbPrefix = $dbPrefix; return $this->mc; } catch (\Exception $e) { Clog::err($e->getMessage()); return false; } } /** * 查询,返回的是光标,也可以用toArray()转换为数组使用 * @author gwang * @param string $collection 集合 * @param array $filter 同过滤器语法 * @param array $options 请利用QueryOptionBuilder()来辅助定制选项 * @return \MongoDB\Driver\Cursor|false 访问光标或者false, 可以用foreach来访问Cursor */ public function find($collection, $filter = [], $options = []) { if (empty($this->mc)) { return false; } try { $query = new \MongoDB\Driver\Query($filter, $options); $cursor = $this->mc->executeQuery($this->dbPrefix . '.' . $collection, $query); return $cursor; } catch (\Exception $ex) { CLog::err($ex->getMessage()); return false; } } /** * 插入1条数据 * @param string $collection 表名(db.collection) * @param array $addArr 待插入的数据,要求是数组 * @return boolean */ public function insert($collection, $addArr) { if (empty($addArr) || !is_array($addArr)) { return false; } if (empty($this->mc)) { return false; } try { $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->insert($addArr); $writeConcern = new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 6000); $result = $this->mc->executeBulkWrite($this->dbPrefix . '.' . $collection, $bulk, $writeConcern); if ($result->getInsertedCount()) { return true; } } catch (\Exception $e) { CLog::err($e->getMessage()); # 记录错误日志 } return false; } /** * 删除 * @param string $collection 表名 * @param array $whereArr 筛选条件 * @param bool $limit 是否仅删除第一条(默认false,删除所有匹配条目) * @return boolean */ public function delete($collection, $whereArr, $limit = false) { if (empty($whereArr)) { return false; } $options = ['limit' => $limit ? 1 : 0]; $conn = $this->mc; if (empty($conn)) { return false; } try { $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->delete($whereArr, $options); $writeConcern = new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 30000); $result = $conn->executeBulkWrite($this->dbPrefix . '.' . $collection, $bulk, $writeConcern); return $result->getDeletedCount(); } catch (\Exception $e) { CLog::err($e->getMessage()); # 记录错误日志 } return false; } /** * 更新 * @param string $collection * @param array $whereArr 条件 * @param array $newPropertiesArr 可以是一个新文档, 也可以是一个opration数组(eg. $set表达式), 还可以是一组update 管道(批量参考https://docs.mongodb.com/manual/reference/command/update/#update-with-an-aggregation-pipeline) * @param bool $upsert 当符合条件的文档不存在时是否作为一条新的文档插入(当新数据为文档时生效,operation不可以) * @param bool $multi 是否一次更新多个文档的值(当新数据为operation表达式时可以,否则不可以) 默认false * @return boolean */ public function update($collection, $whereArr, $newPropertiesArr, $upsert = true, $multi = false) { if (empty($whereArr) || empty($newPropertiesArr)) { return false; } $options = ['multi' => $multi, 'upsert' => $upsert]; $conn = $this->mc; if (empty($conn)) { return false; } try { $bulk = new \MongoDB\Driver\BulkWrite(); $bulk->update($whereArr, $newPropertiesArr, $options); $writeConcern = new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 30000); $result = $conn->executeBulkWrite($this->dbPrefix . '.' . $collection, $bulk, $writeConcern); return $result->getUpsertedCount() + $result->getModifiedCount(); } catch (\Exception $e) { CLog::err($e->getMessage()); # 记录错误日志 } return false; } } /** * 查询选项构造器 * @author gwang */ class MongoQueryOptionBuilder { /** * 内部对象 */ private $option = array(); /** * 返回最终的 options * @return array */ public function GetOption() { return $this->option; } /** * 参照MySQL的 explain * @param bool $yes * @return MongoQueryOptionBuilder */ public function explain($yes = true) { $this->option[__FUNCTION__] = $yes; return $this; } /** * 限定返回值数量(0=无限制) * @param int $limit 默认 0 * @return MongoQueryOptionBuilder */ public function limit($limit = 0) { $this->option[__FUNCTION__] = $limit; return $this; } /** * 限定返回值跳过前n个文档(索引从0开始) * @param int $n 默认值0 * @return MongoQueryOptionBuilder */ public function skip($n = 0) { $this->option[__FUNCTION__] = $n; return $this; } /** * project * @param array $arr 假如MQL中为{$project:{key:1,name:"$value.baseInfo.name"}} * 则此处['key'=>1,'name'=>'$value.baseInfo.name'] 注意如果包含$符使用单引号 * @return MongoQueryOptionBuilder */ public function projection($arr = array()) { $this->option[__FUNCTION__] = $arr; return $this; } /** * 必须与 tailable awaitData 结合使用. * 设定正整数值可以让服务器阻塞对应的毫秒数(没有数据的前提下,有数据自然直接返回) * @param int $n * @return MongoQueryOptionBuilder */ public function maxAwaitTimeMS($n = 0) { $this->option[__FUNCTION__] = $n; return $this; } /** * 只返回索引 * @param bool $yes 默认值false, 当设为true时,你应该了解会返回什么. * @return $this */ public function returnKey($yes = false) { $this->option[__FUNCTION__] = $yes; return $this; } /** * The sort specification for the ordering of the results. * Falls back to the deprecated modifier if not specified. "$orderby" * @param array $arr 假如MQL中为{$sort:{"value.baseInfo.level":-1}则对应["value.baseInfo.level"=>-1] * @return MongoQueryOptionBuilder */ public function sort($arr = array()) { $this->option[__FUNCTION__] = $arr; return $this; } // /** * 不了解, 先不要使用 * @deprecated since version 0 * @param type $yes * @return $this */ public function allowDiskUse($yes = true) { $this->option[__FUNCTION__] = $yes; return $this; } /** * 不了解, 先不要使用 * @deprecated since version 0 * @param type $yes * @return $this */ public function allowPartialResults($yes = true) { $this->option[__FUNCTION__] = $yes; return $this; } /** * 不了解, 先不要使用 * @deprecated since version 0 * @param type $yes * @return $this */ public function awaitData($yes = true) { $this->option[__FUNCTION__] = $yes; return $this; } /** * 返回值第一批的文档数,默认值为101,设置为0表示将建立光标,但不返回任何文档 * @deprecated since version 0 不懂,先不要用 * @param type $size * @return MongoQueryOptionBuilder */ public function batchSize($size = 101) { $this->option[__FUNCTION__] = $size; return $this; } /** * 语言设置 * @deprecated since version 0 这个太复杂还没研究,先不要用 * @param array|object $collation * @return MongoQueryOptionBuilder */ public function collation($collation = array()) { $this->option[__FUNCTION__] = $collation; return $this; } /** * 注释 * @param type $msg * @return MongoQueryOptionBuilder */ public function comment($msg = "默认注释") { $this->option[__FUNCTION__] = $msg; return $this; } /** * 尽最大努力下载数据,(从3.2+已经不再支持) * @deprecated since version mongodb 3.2+ * @param type $yes * @return MongoQueryOptionBuilder */ public function exhaust($yes = true) { $this->option[__FUNCTION__] = $yes; return $this; } /** * 不懂, 先不要用 * @deprecated since version 0 在某个index的上限(不包含上限值) * @param array $arr * @return MongoQueryOptionBuilder */ public function max($arr = array()) { $this->option[__FUNCTION__] = $arr; return $this; } /** * 不懂,先不要用 * @deprecated since version 0 在某个index的下限(包含下限值) * @param array $arr * @return MongoQueryOptionBuilder */ public function min($arr = array()) { $this->option[__FUNCTION__] = $arr; return $this; } /** * @deprecated since version 0 已经废弃 * @param int $i * @throws \Exception */ public function maxScan($i = 0) { throw new \Exception("Deprecated!"); } /** * Determines whether to close the cursor after the first batch. Defaults to false. * @param bool $yes * @deprecated since version 0 不放心, 先不要用 * @return MongoQueryOptionBuilder */ public function singleBatch($yes = false) { $this->option[__FUNCTION__] = $yes; return $this; } /** * Determines whether to return the record identifier for each document. * If true, adds a top-level field to the returned documents. "$recordId" * @deprecated since version 0 这个感觉没啥用,也没测试过,先不要用 * @param bool $yes * @return $this */ public function showRecordId($yes = false) { $this->option[__FUNCTION__] = $yes; return $this; } /** * Returns a tailable cursor for a capped collection. * @deprecated since version 0 不懂,先不要用 * @param type $yes * @return MongoQueryOptionBuilder */ public function tailable($yes = false) { $this->option[__FUNCTION__] = $yes; return $this; } // }