在skynet中使用mongodb,在
在配置文件config.mongodb中看到启动的是main_mongodb.lua
main_mongodb.lua文件内容
local skynet = require "skynet"
skynet.start(function()
print("Main Server start")
local console = skynet.newservice(
"testmongodb", "127.0.0.1", 27017, "testdb", "test", "test"
)
print("Main Server exit")
skynet.exit()
end)
testmongodb.lua文件在官方的示例中有,大家可以自己去看,我们这里不展开。
接下来要说的是,在skynet中,我们怎么更方便地使用mongodb。
我们考虑的是将mongodb单独成一个服务,
在使用时候,用skynet.call去调用它,示例:
local mongodb = skynet.newservice("mongodb")
skynet.call(mongodb, "lua", "connect", {
host = "127.0.0.1",
port = 27017
})
第一个文件:
mongodb.lua
local skynet = require "skynet"
require "skynet.manager"
local dbLogic = require "dbLogic"
skynet.start(function()
skynet.dispatch("lua", function(session, address, cmd, ...)
local f = dbLogic[cmd]
if f then
skynet.ret(skynet.pack(f(...)))
else
error(string.format("Unknown command %s", tostring(cmd)))
end
end)
skynet.register ".mongodb"
end)
我们把对mongodb的增、删、查、改都放到了dbLogic.lua文件中:
local skynet = require "skynet"
require "skynet.manager"
local mongo = require "skynet.db.mongo"
local client
local _M = {}
function _M.connect(args)
client = mongo.client(
{
host = args.host,
port = tonumber(args.port)
}
)
if client then
return true
end
return false
end
function _M.disconnect()
client:disconnect()
end
function _M.insert(args)
local db = client:getDB(args.database)
local c = db:getCollection(args.collection)
c:insert(args.doc)
end
function _M.insertBatch(args)
local db = client:getDB(args.database)
local c = db:getCollection(args.collection)
c:batch_insert(args.docs)
end
function _M.delete(args)
local db = client:getDB(args.database)
local c = db:getCollection(args.collection)
c:delete(args.selector, args.single)
end
function _M.drop(args)
local db = client:getDB(args.database)
local r = db:runCommand("drop", args.collection)
return r
end
function _M.findOne(args)
local db = client:getDB(args.database)
local c = db:getCollection(args.collection)
local result = c:findOne(args.query, args.selector)
return result
end
function _M.findAll(args)
local db = client:getDB(args.database)
local c = db:getCollection(args.collection)
local result = {}
local cursor = c:find(args.query, args.selector)
if args.skip ~= nil then
cursor:skip(args.skip)
end
if args.limit ~= nil then
cursor:limit(args.limit)
end
while cursor:hasNext() do
local document = cursor:next()
table.insert(result, document)
end
cursor:close()
if #result > 0 then
return result
end
end
function _M.update(args)
local db = client:getDB(args.database)
local c = db:getCollection(args.collection)
c:update(args.selector, args.update, args.upsert, args.multi)
end
function _M.createIndex(args)
local db = client:getDB(args.database)
local c = db:getCollection(args.collection)
local result = c:createIndex(args.keys, args.option)
return result
end
function _M.runCommand(args)
local db = client:getDB(args.database)
local result = db:runCommand(args)
return result
end
return _M
为了方便查看table中的数据,我们将util.lua拷贝过来,放到和main.lua同一个文件下。
具体内容查看这篇博客:https://blog.csdn.net/hp_cpp/article/details/104882400
现在我们开始对dbLogic.lua的接口进行测试和说明:
一、连接数据库
local skynet = require "skynet"
local util = require "util"
skynet.start(function()
print("Main Server start")
local mongodb = skynet.newservice("mongodb")
local ret = skynet.call(mongodb, "lua", "connect", {
host = "127.0.0.1",
port = 27017
})
print("connect ret:", ret)
--以下测试均在此处添加代码
skynet.exit()
end)
打印出true,表示连接成功。
我们现在用的mongo数据库在默认端口,没有用户名和密码的,而连接数据库也很简单,只需要提供两个参数host和port:
client = mongo.client({host = args.host,
port = tonumber(args.port)})
我们手动建一个testdb数据库,以下操作均在testdb数据中进行。
二、插入
(1)单条插入
skynet.call(mongodb, "lua", "insert", {
database = "testdb",
collection = "role",
doc = {test = "haha", num = 100}
})
这个操作在dbLogic.lua文件没有定义返回值,所以我们去查看数据库,果然新增了一个role表和插入一条记录
(1)批量插入
skynet.call(mongodb, "lua", "insertBatch", {
database = "testdb",
collection = "role",
docs = {
{test = "hi", num = 101},
{test = "me to", num = 102}}
})
此时role表中又多了几条记录。
三、删除
(1)删除记录
skynet.call(mongodb, "lua", "delete", {
database = "testdb",
collection = "role",
selector = {num=100},
single = 1,
})
这里删除了role表中所有num=100的记录,(single为整形,表示删除多少条记录,或者说是删除多少个doc),具体可以查看以下两个文件:
在skynet-master\lualib\skynet\db\mongo.lua文件中:
function mongo_collection:delete(selector, single)
local sock = self.connection.__sock
local pack = driver.delete(self.full_name, single, bson_encode(selector))
sock:request(pack)
end
在去查skynet-master\lualib-src\lua-mongo.c文件:
/*
1 string collection
2 integer single remove
3 document selector
return string package
*/
static int
op_delete(lua_State *L) {
document selector = lua_touserdata(L,3);
if (selector == NULL) {
luaL_error(L, "Invalid param");
}
size_t sz = 0;
const char * name = luaL_checklstring(L,1,&sz);
luaL_Buffer b;
luaL_buffinit(L,&b);
struct buffer buf;
buffer_create(&buf);
int len = reserve_length(&buf);
write_int32(&buf, 0);
write_int32(&buf, 0);
write_int32(&buf, OP_DELETE);
write_int32(&buf, 0);
write_string(&buf, name, sz);
write_int32(&buf, lua_tointeger(L,2));
int32_t selector_len = get_length(selector);
int total = buf.size + selector_len;
write_length(&buf, total, len);
luaL_addlstring(&b, (const char *)buf.ptr, buf.size);
buffer_destroy(&buf);
luaL_addlstring(&b, (const char *)selector, selector_len);
luaL_pushresult(&b);
return 1;
}
(2)清空表
ret = skynet.call(mongodb, "lua", "drop", {
database = "testdb",
collection = "role",
})
util.dump_table(ret)
输出结果:
S:nIndexesWas -> N:1
S:ok -> N:1.0
S:ns -> S:testdb.role
此时看到
role中的记录全部删除
返回的是一个table,我们用util模块中的util.dump_table打印出来,看到有个ok = 1.0,通过比较这个ok是否等于1,我们可以知道该操作是否成功
如果我们再执行一遍清空表操作:
则运行结果:
S:errmsg -> S:ns not found
S:ok -> N:0.0
S:code -> N:26
S:codeName -> S:NamespaceNotFound
提示我们操作错误了。
四、查找
(1)查找单条记录
ret = skynet.call(mongodb, "lua", "findOne", {
database = "testdb",
collection = "role",
query = {num = 100},
selector = {test=1}
})
util.dump_table(ret)
当找到该文档时,输出:
S:_id -> S:^n��(�G�g�
S:test -> S:haha
没找到时,返回nil
这里的参数要说明一下:
query是查询条件,{num = 100},这里可以写多个条件。
selector是刷选器,也就是最后结果中需要的字段(除_id外,其余字段),比如我们这里只填入了一个test=1,这里的筛选的字段要作为key,如果是空表,则表示全部字段都要。
ret = skynet.call(mongodb, "lua", "findOne", {
database = "testdb",
collection = "role",
query = {num = 100},
selector = {}
})
运行结果:
S:test -> S:haha
S:num -> N:100
S:_id -> S:^n��(��wf�
(1)查找全部
ret = skynet.call(mongodb, "lua", "findAll", {
database = "testdb",
collection = "role",
query = {num = 100},
selector = {test=1}
})
util.dump_table(ret)
参数说明同上,只是这里的返回值略有不同,返回多条记录。(比如role表中有3条记录)
N:1 ->
S:_id -> S:^n��(��wf�
S:test -> S:haha
N:2 ->
S:_id -> S:^n��(��7f�
S:test -> S:haha
N:3 ->
S:_id -> S:^nF�(���
S:test -> S:haha
五、修改
local updater = {}
updater["$set"] = {test = "hello world1"}
local allResult = skynet.call(mongodb, "lua", "update", {
database = "testdb",
collection = "role",
selector = {num=100},
update = updater,
upsert = false,
multi = false
})
util.dump_table(ret)
参数说明:
updater用来设置更新字段和内容
这里updater["$set"]是固定格式,后面是一个表,记录需要修改的字段和内容。
updater["$set"] = {test = "hello world1"}
upsert 布尔值,true表示不存在则新增一条新文档,false表示不存在则不做任何操作
multi 布尔值,true表表示多行更新,flase表示只会更新符合条件的一条记录
main.lua中的全部代码:
local skynet = require "skynet"
local util = require "util"
skynet.start(function()
print("Main Server start")
local mongodb = skynet.newservice("mongodb")
local ret = skynet.call(mongodb, "lua", "connect", {
host = "127.0.0.1",
port = 27017
})
print("connect ret:", ret)
skynet.call(mongodb, "lua", "insert", {
database = "testdb",
collection = "role",
doc = {test = "haha", num = 100}
})
-- skynet.call(mongodb, "lua", "insertBatch", {
-- database = "testdb",
-- collection = "role",
-- docs = {
-- {test = "hi", num = 101},
-- {test = "me to", num = 102}}
-- })
-- skynet.call(mongodb, "lua", "delete", {
-- database = "testdb",
-- collection = "role",
-- selector = {num=100},
-- single = 1,
-- })
-- ret = skynet.call(mongodb, "lua", "drop", {
-- database = "testdb",
-- collection = "role",
-- })
-- util.dump_table(ret)
-- ret = skynet.call(mongodb, "lua", "findOne", {
-- database = "testdb",
-- collection = "role",
-- query = {num = 100},
-- selector = {}
-- })
-- util.dump_table(ret)
-- ret = skynet.call(mongodb, "lua", "findAll", {
-- database = "testdb",
-- collection = "role",
-- query = {num = 100},
-- selector = {test=1}
-- })
-- util.dump_table(ret)
-- local updater = {}
-- updater["$set"] = {test = "hello world1"}
-- local allResult = skynet.call(mongodb, "lua", "update", {
-- database = "testdb",
-- collection = "role",
-- selector = {num=100},
-- update = updater,
-- upsert = false,
-- multi = false
-- })
-- util.dump_table(ret)
skynet.exit()
end)
util.lua中的全部代码:
local util = {}
local function get_type_first_print( t )
local str = type(t)
return string.upper(string.sub(str, 1, 1))..":"
end
function util.dump_table(t, prefix, indent_input, print)
local indent = indent_input
if indent_input == nil then
indent = 1
end
if print == nil then
print = _G["print"]
end
local p = nil
local formatting = string.rep(" ", indent)
if prefix ~= nil then
formatting = prefix .. formatting
end
if t == nil then
print(formatting.." nil")
return
end
if type(t) ~= "table" then
print(formatting..get_type_first_print(t)..tostring(t))
return
end
local output_count = 0
for k,v in pairs(t) do
local str_k = get_type_first_print(k)
if type(v) == "table" then
print(formatting..str_k..k.." -> ")
util.dump_table(v, prefix, indent + 1,print)
else
print(formatting..str_k..k.." -> ".. get_type_first_print(v)..tostring(v))
end
output_count = output_count + 1
end
if output_count == 0 then
print(formatting.." {}")
end
end
return util
最后的最后:
通过传入不同参数,可以通过runCommand,可以扩展我们对mongodb的操作。
function _M.runCommand(args)
local db = client:getDB(args.database)
local result = db:runCommand(args)
return result
end
参考:
lua打印table