skynet框架应用——mongodb

在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

Mongodb 更新操作update

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值