【MongoDB】Ubuntu22.04 下安装 MongoDB | 用户权限认证 | skynet.db.mongo 模块使用

文章目录

Ubuntu 22.04 安装 MongoDB

其他平台安装教程可参考官网:https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-ubuntu/


  1. 确定主机运行哪个 Ubuntu 版本:(配置一致的继续往下看)

    cat /etc/lsb-release

  1. 安装 mongodb 社区版的相关依赖

    sudo apt-get install libcurl4 libgssapi-krb5-2 libldap-2.5-0 libwrap0 libsasl2-2 libsasl2-modules libsasl2-modules-gssapi-mit openssl liblzma5 gnupg curl

  2. 导入 MongoDB 公共 GPG 密钥

    curl -fsSL https://pgp.mongodb.com/server-7.0.asc |
    sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg
    --dearmor

  3. 创建/etc/apt/sources.list.d/mongodb-org-7.0.list 列表文件

    echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list

  4. 重新加载本地包数据库

    sudo apt-get update

  5. 安装最新的稳定版本

    sudo apt-get install -y mongodb-org


后台启动 MongoDB

  • 配置 /etc/mongod.conf

    • bindIp: 0.0.0.0
    • fork: true
shell 复制代码
# mongod.conf

# for documentation of all options, see:
#   http://docs.mongodb.org/manual/reference/configuration-options/

# Where and how to store data.
storage:
  dbPath: /var/lib/mongodb
#  engine:
#  wiredTiger:

# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log

# network interfaces
net:
  port: 27017
  bindIp: 0.0.0.0


# how the process runs
processManagement:
  fork: true
  timeZoneInfo: /usr/share/zoneinfo

#security:

#operationProfiling:

#replication:

#sharding:

## Enterprise-Only Options:

#auditLog:
  • sudo mongod -f /etc/mongod.conf

执行后结果如下:

shell 复制代码
about to fork child process, waiting until server is ready for connections.
forked process: 361
child process started successfully, parent exiting
  • ps -ef | grep mongod:可以看到有mongod进程在后台运行

shell 连入 MongoDB 服务

  • mongosh:mongodb 客户端连接工具(安装时自带)

成功连入使用:


MongoDB 用户权限认证

创建 root 用户

在 MongoDB 中,root 账号是具有最高权限的账号,可以执行所有操作。

lua 复制代码
use admin
db.createUser({user:'root', pwd:'root',roles:['root']})

开启认证

我们需要开启 MongoDB 的认证功能,以确保只有经过认证的用户才能访问数据库。

  • /etc/mongod.conf

在启动配置文件中,添加以下配置:

lua 复制代码
security:
  authorization: enabled

重启 MongoDB 服务,认证功能才会生效。

重启 MongoDB 服务

官方描述:Sending a KILL signal kill -9 will probably cause damage as mongod will not be able to cleanly exit. (In such a scenario, run the repairDatabase command.)

可以采用在 mongosh 连入数据库后,执行下述指令来友好关闭服务进程。

lua 复制代码
use admin
db.shutdownServer()

创建其他用户

在MongoDB中,每个数据库都有自己的权限系统,可以为每个数据库创建不同的账号并赋予不同的角色。

lua 复制代码
db.createUser({user: 'cauchy', pwd: 'root', roles: [{ role: 'readWrite', db: 'test'}]})

readWrite: https://www.mongodb.com/docs/manual/reference/built-in-roles/#mongodb-authrole-readWrite

roles 可参考:https://www.mongodb.com/docs/manual/reference/built-in-roles/

查看用户信息

执行下述指令,查看当前数据库系统中的所有用户信息:

lua 复制代码
use admin
db.system.users.find()

验证用户权限

在 test 数据库中,验证当前 cauchy 用户权限

lua 复制代码
use test
db.auth('cauchy', 'root')

删除用户

lua 复制代码
use test
db.dropUser('cauchy')

skynet.db.mongo 模块使用

本节主要讲解在 Skynet 框架中一些常用的 API,以及如何使用相应的 API 来执行 MongoDB 的 CRUD。

前置变量、方法:

lua 复制代码
host = "127.0.0.1"
port = 27017
username = "cauchy"
password = "root"
authdb = "test"
db_name = "test"

function create_client()
	return mongo.client({
		host = host, 
		port = port,
		username = username,
		password = password, 
		authdb = authdb
	})
end 

auth

数据库连接认证

  • 用法:db:auth(user, pwd)

测试代码:

lua 复制代码
function test_auth()
	local ok, err, ret
	local c = mongo.client({
			host = host, 
			port = port,
		}
	)
	local db = c[db_name]
	db:auth(username, password)

	db.testcol:dropIndex("*")
	db.testcol:drop()

	ok, err, ret = db.testcol:safe_insert({test_key = 1});
	assert(ok and ret and ret.n == 1, err)
end 

如果注释掉认证:-- db:auth(username, password),则会报错提示需要权限认证。


ensureIndex

创建索引

  • 用法:db.collection:ensureIndex({ key1 }, { option })

源码 mongo.lua 中,这个 API 实际上就是创建索引:

lua 复制代码
mongo_collection.ensureIndex = mongo_collection.createIndex

测试代码:

lua 复制代码
function test_insert_with_index()
	local ok, err, ret
	local c = create_client()
	local db = c[db_name]

	db.testcol:dropIndex("*")
	db.testcol:drop()

	db.testcol:ensureIndex({test_key = 1}, {unique = true, name = "test_key_index"})
	--[[ mongosh
		db.testcol.getIndexes()
	]]

	ok, err, ret = db.testcol:safe_insert({test_key = 1})
	assert(ok and ret and ret.n == 1, err)

	ok, err, ret = db.testcol:safe_insert({test_key = 1})
	assert(ok == false and string.find(err, "duplicate key error"))
end

执行结果:


find、findOne

查找符合条件的文档,find 查找所有,findOne 查找第一条

  • 用法:db.collection:find(query, projection)db.collection:findOne(query, projection)
  • projection:查询结果的投影

源码:(nextfindfindOne

lua 复制代码
local mongo_cursor = {}
local cursor_meta =	{
	__index	= mongo_cursor,
}
------------------------------------------------------------------------------------------------------
function mongo_cursor:next()
	if self.__ptr == nil then
		error "Call	hasNext	first"
	end
	local r	= self.__document[self.__ptr]
	self.__ptr = self.__ptr	+ 1
	if self.__ptr >	#self.__document then
		self.__ptr = nil
	end

	return r
end
------------------------------------------------------------------------------------------------------
function mongo_collection:findOne(query, projection)
	local cursor = self:find(query, projection)
	if cursor:hasNext() then
		return cursor:next()
	end
	return nil
end
------------------------------------------------------------------------------------------------------
function mongo_collection:find(query, projection)
	return setmetatable( {
		__collection = self,
		__query	= query	and	bson_encode(query) or empty_bson,
		__projection = projection and bson_encode(projection) or empty_bson,
		__ptr =	nil,
		__data = nil,
		__cursor = nil,
		__document = {},
		__flags	= 0,
		__skip = 0,
		__limit = 0,
		__sort = empty_bson,
	} ,	cursor_meta)
end
  1. 简单查看上述源码,可以发现 cursor:next 返回 __document 中的内容,即为实际找到的文档内容。

  2. find 返回一张表,表中有很多字段(__collection__cursor__document 等),这张表的元表是 cursor_meta,而 cursor_meta 的属性 __index 是表 mongo_cursor。所以在用 find 查找符合条件的文档时,返回的值应该使用 next 方法去一个个遍历获取所有的返回结果,即为 __document 中的内容。

  3. findOne 直接就是返回查找到的第一个文档,如上述 return cursor:next()


insert、safe_insert

插入一条文档

  • 用法:db.collection:insert(doc)db.collection:safe_insert(doc)

源码:

lua 复制代码
function mongo_collection:insert(doc)
	if doc._id == nil then
		doc._id	= bson.objectid()
	end
	self.database:send_command("insert", self.name, "documents", {bson_encode(doc)})
end
------------------------------------------------------------------------------------------------------
function mongo_collection:safe_insert(doc)
	local r = self.database:runCommand("insert", self.name, "documents", {bson_encode(doc)})
	return werror(r)
end

如上述源码,safe_insert 会返回一些相关信息(由 werror 返回),而 insert 没有任何返回值。


delete、safe_delete

删除符合条件的一条或多条文档

  • 用法:db.collection:delete(query, single)db.collection:safe_delete(query, single)
  • single:删除条数(即limit限制)

源码:

lua 复制代码
function mongo_collection:delete(query, single)
	self.database:runCommand("delete", self.name, "deletes", {bson_encode({
		q = query,
		limit = single and 1 or 0,
	})})
end
------------------------------------------------------------------------------------------------------
function mongo_collection:safe_delete(query, single)
	local r = self.database:runCommand("delete", self.name, "deletes", {bson_encode({
		q = query,
		limit = single and 1 or 0,
	})})
	return werror(r)
end

如上述源码,safe_delete 会返回一些相关信息(由 werror 返回),而 delete 没有任何返回值。

测试代码:

lua 复制代码
function test_find_and_remove()
	local ok, err, ret
	local c = create_client()
	local db = c[db_name]

	db.testcol:dropIndex("*")
	db.testcol:drop()

	local cursor = db.testcol:find()
	assert(cursor:hasNext() == false)

	db.testcol:ensureIndex({test_key = 1}, {test_key2 = -1}, {unique = true, name = "test_index"})

	ok, err, ret = db.testcol:safe_insert({test_key = 1, test_key2 = 1})
	assert(ok and ret and ret.n == 1, err)

	cursor = db.testcol:find()
	assert(cursor:hasNext() == true)
	local v = cursor:next()
	assert(v)
	assert(v.test_key == 1)

	ok, err, ret = db.testcol:safe_insert({test_key = 1, test_key2 = 2})
	assert(ok and ret and ret.n == 1, err)

	ok, err, ret = db.testcol:safe_insert({test_key = 2, test_key2 = 3})
	assert(ok and ret and ret.n == 1, err)

	ret = db.testcol:findOne({test_key2 = 1})
	assert(ret and ret.test_key2 == 1, err)

	ret = db.testcol:find({test_key2 = {['$gt'] = 0}}):sort({test_key = 1}, {test_key2 = -1}):skip(1):limit(1)
	--[[ mongosh
		db.testcol.find({test_key2: {$gt: 0}}).sort({test_key: 1}, {test_key2: -1}).skip(1).limit(1)
	]]
	assert(ret:count() == 3)
	assert(ret:count(true) == 1)
	if ret:hasNext() then
		ret = ret:next()
	end
	assert(ret and ret.test_key2 == 1)

	db.testcol:delete({test_key = 1})
	db.testcol:delete({test_key = 2})

	ret = db.testcol:findOne({test_key = 1})
	assert(ret == nil)
end

上述代码中有调用了sortskiplimit,如源码所示,即为 find 返回的表中,__sort__skip__limit字段附上了值,而不是直接对数据执行排序,跳转、约束等操作。

  • count 比较特殊,会实际执行一次指令 runCommand,需要参数 with_limit_and_skip。如果参数为 nilfalse,则执行会忽略 skiplimit,反之,会加上。

源码(sortskiplimitcount ):

lua 复制代码
-- cursor:sort { key = 1 } or cursor:sort( {key1 = 1}, {key2 = -1})
function mongo_cursor:sort(key, key_v, ...)
	if key_v then
		local key_list = unfold({}, key, key_v , ...)
		key = bson_encode_order(table.unpack(key_list))
	end
	self.__sort = key
	return self
end

function mongo_cursor:skip(amount)
	self.__skip = amount
	return self
end

function mongo_cursor:limit(amount)
	self.__limit = amount
	return self
end

function mongo_cursor:count(with_limit_and_skip)
	local cmd = {
		'count', self.__collection.name,
		'query', self.__query,
	}
	if with_limit_and_skip then
		local len = #cmd
		cmd[len+1] = 'limit'
		cmd[len+2] = self.__limit
		cmd[len+3] = 'skip'
		cmd[len+4] = self.__skip
	end
	local ret = self.__collection.database:runCommand(table.unpack(cmd))
	assert(ret and ret.ok == 1)
	return ret.n
end

update、safe_update

更新一条文档

  • 用法:db.collection:update(query,update,upsert,multi)db.collection:safe_update(query,update,upsert,multi)
  • upsert : 默认是false。如果不存在 query 对应条件的文档,是 true 则插入一条新文档,false 则不插入。
  • multi : 默认是 false,只更新找到的第一条记录。是 true,就把按条件查出来多条记录全部更新。

示例代码:

lua 复制代码
function test_update()
	local ok, err, r
	local c = create_client()
	local db = c[db_name]
	db.testcol:dropIndex("*")
	db.testcol:drop()

	db.testcol:safe_insert({test_key = 1, test_key2 = 1})
	db.testcol:safe_insert({test_key = 1, test_key2 = 2})

	-- ok, err, r = db.testcol:safe_update({test_key2 = 2}, { ['$set'] = {test_key = 2} }, true, false)
	-- assert(ok and r and r.n == 1)
	ok, err, r = db.testcol:safe_update({test_key = 1}, { ['$set'] = {test_key2 = 3} }, true, true)
	assert(ok and r and r.n == 2)
end 

aggregate

聚合,将来自多个 doc 的 value 组合在一起,并通过对分组数据进行各种操作处理,返回计算后的数据结果,主要用于处理数据(例如统计平均值,求和等)。

  • 用法:db.collection:aggregate({ { ["$project"] = {tags = 1} } }, {cursor={}})
  • @param pipeline: array
  • @param options: map

测试代码:

lua 复制代码
function test_runcommand()
	local ok, err, ret
	local c = create_client()
	local db = c[db_name]

	db.testcol:dropIndex("*")
	db.testcol:drop()

	ok, err, ret = db.testcol:safe_insert({test_key = 1, test_key2 = 1})
	assert(ok and ret and ret.n == 1, err)

	ok, err, ret = db.testcol:safe_insert({test_key = 1, test_key2 = 2})
	assert(ok and ret and ret.n == 1, err)

	ok, err, ret = db.testcol:safe_insert({test_key = 2, test_key2 = 3})
	assert(ok and ret and ret.n == 1, err)

	local pipeline = {
		{
			["$group"] = {
				_id = mongo.null,
				test_key_total = { ["$sum"] = "$test_key"},
				test_key2_total = { ["$sum"] = "$test_key2" },
			}
		}
	}
	ret = db:runCommand("aggregate", "testcol", "pipeline", pipeline, "cursor", {})
	assert(ret and ret.cursor.firstBatch[1].test_key_total == 4)
	assert(ret and ret.cursor.firstBatch[1].test_key2_total == 6)
	
	local res = db.testcol:aggregate(pipeline, {cursor={}})
	assert(res and res.cursor.firstBatch[1].test_key_total == 4)
	assert(res and res.cursor.firstBatch[1].test_key2_total == 6)
end

官方的 aggregate 接口手册:https://www.mongodb.com/docs/manual/reference/command/aggregate/


safe_batch_insert、safe_batch_delete

批量插入和删除

  • 用法:db.collection:safe_batch_insert(docs)db.collection:safe_batch_delete(docs)

测试代码:

lua 复制代码
function test_batch_insert_delete()
	local ok, err, ret
	local c = create_client()
	local db = c[db_name]

	db.testcol:dropIndex("*")
	db.testcol:drop()

	local insert_docs = {}
	local insert_length = 10
	for i = 1, insert_length do 
		table.insert(insert_docs, {test_key = i})
	end 
	db.testcol:safe_batch_insert(insert_docs)
	ret = db.testcol:find()
	assert(insert_length == ret:count(), "test safe batch insert failed")

	local delete_docs = {}
	local delete_length = 5
	for i = 1, delete_length do 
		table.insert(delete_docs, {test_key = i})
	end 
	db.testcol:safe_batch_delete(delete_docs)

	assert(ret:count() == insert_length - delete_length, "test safe batch delete failed")
end 

更多的 skynet.db.mongo 模块用法可以去源码阅读查看。

附上 MongoDB 7.0 Manual

相关推荐
源代码:趴菜3 分钟前
MySQL函数:数值函数
数据库·mysql
Data 31723 分钟前
经典sql题(八)SQL 查询详细指南总结一
大数据·数据库·数据仓库·sql·mysql
酷帅且洋仔26 分钟前
Redis——常用数据类型hash
数据库·redis
你可以自己看36 分钟前
python中Web开发框架的使用
数据库·python·sqlite
脚步的影子42 分钟前
2024最新版MySQL详细学习教程
数据库·学习·mysql
消失在人海中44 分钟前
oracle表的类型
数据库·oracle·表的类型
J总裁的小芒果1 小时前
Mysql SqlServer 分页
数据库·mysql·sqlserver
Ja_小浩1 小时前
【MySQL】MySQL的数据类型
数据库·mysql
毅凉2 小时前
Linux笔记
linux·c语言·网络·数据库
罗小爬EX3 小时前
MySql批量迁移数据库
数据库·mysql