mongodb-erlang 是一个非官方的MongoDB客户端,提供了Erlang语言版本的MongoDB驱动。本文旨在通过对其文档和源码的分析探索其使用方法,解析其工作方式。
我们假定读者已经有了如下的知识储备:
- Erlang语言的语法和OTP的的基本使用方法
- MongoDB的基本用法
- Erlang进程池管理项目poolboy的基本用法
文章目录
文档解析
我们从文档可以得知,该项目有两个api模块:mc_worker_api.erl
和mongo_api.erl
。mc_worker_api.erl
会建立单独的连接与MongoDB进行交互,mongo_api.erl
则会建立连接池,管理与MongoDB的多个连接。
文档还提到了,如果要在官方提供的mongos(MongoDB分片集群路由)和通过mongo_api.erl
连接shard(分片)之间进行选择,建议使用mongos + mc_worker_api.erl
的组合。
连接
使用mc_worker_api:connect/1
连接MongoDB数据库:
Database = <<"test">>.
{
ok, Connection} = mc_worker_api:connect ([{
database, Database}]).
建立连接时可以传递一些参数,具体的参数见文档,为了方面后面对源码的理解,我们来分析其中几个参数:
- login和password:不解释。
- w_mode:如果设置为
safe|{safe,GetLastErrorParams}
,进程会在每次写入后发送getLastError请求,如果MongoDB报告写入错误,则剩余的写入会被中断并返回{failure, {write_failure, Reason}}
错误;如果设置为unsafe
,则假定每次写入必定成功,写入失败会被忽略。 - next_req_fun:会在进程每次向MongoDB发送请求后执行,可以用来优化进程池性能(It can be use to optimise pool usage)。如果使用的是poolboy,可以用
{next_req_fun, fun() -> poolboy:checkin(?DBPOOL, self()) end}
使得工作进程(worker)在发送请求后马上被进程池回收(poolboy的进程池启动策略需要是{strategy,fifo}
)。
关于GetLastErrorParams,在MongoDB关于getLastError的文档写到:
Changed in version 2.6: A new protocol for write operations integrates write concerns with the write operations, eliminating the need for a separate getLastError.
就是说getLastError已经在2.6之后的Database Command已经用不上了,但在MongoDB Wire Protocol里还保留着,这点值得留意。
写入
这几种都属于写方法。可以使用mc_worker_api:insert
,mc_worker_api:update
和mc_worker_api:delete
完成数据库写入操作。
插入maps:
Collection = <<"test">>.
mc_worker_api:insert(Connection, Collection, #{
<<"name">> => <<"Yankees">>, <<"home">> =>
#{
<<"city">> => <<"New York">>, <<"state">> => <<"NY">>}, <<"league">> => <<"American">>}),
删除文档,需要指定Selector:
mc_worker_api:delete(Connection, Collection, Selector).
读取
使用mc_worker_api:find
,mc_worker_api:find_one
读取数据:
{
ok, Cursor} = mc_worker_api:find(Connection, Collection, Selector)
find_one
和find
的不同在于,前者直接返回查询结果(文档),后者返回一个游标(cursor)进程的pid,可以在mc_cursor.erl
模块中查看游标的用法:
Result = mc_cursor:next(Cursor),
mc_cursor:close(Cursor),
除了selector,还可传入projector过滤查询结果:
mc_worker_api:find_one(Connection, Collection, {
}, #{
projector => #{
<<"value">> => true}).
更新
使用mc_worker_api:update
和$set
进行更新,不多解释:
Command = #{
<<"$set">> => #{
<<"quantity">> => 500,
<<"details">> => #{
<<"model">> => "14Q3", <<"make">> => "xyz"},
<<"tags">> => ["coats", "outerwear", "clothing"]
}},
mc_worker_api:update(Connection, Collection, #{
<<"_id">> => 100}, Command),
创建索引
使用mc_worker_api:ensure_index/3
创建索引。
mc_worker_api:ensure_index(Connection, Collection, #{
<<"key">> => #{
<<"index">> => 1}}). %simple
mc_worker_api:ensure_index(Connection, Collection, #{
<<"key">> => #{
<<"index">> => 1}, <<"name">> => <<"MyI">>}). %advanced
mc_worker_api:ensure_index(Connection, Collection, #{
<<"key">> => #{
<<