目录
1. MongoDB 笔记 (bson)
1.1. 常用命令行
MongoDB: Create User – For Database, Admin, Root
-
显示所有数据的列表:
show dbs
-
显示当前数据库对象或集合:
dbs
-
运行
use
命令, 可以连接到一个指定的数据库 -
查询服务器状态:
db.runCommand(
{
serverStatus: 1
}
)
-
切换用户:
db.auth("root", "example")
-
创建用户:
db.createUser({
"user": "datakit",
"pwd": "<YOUR_COLLECT_PASSWORD>",
"roles": [
{ role: "read", db: "admin" },
{ role: "clusterMonitor", db: "admin" },
{ role: "backup", db: "admin" },
{ role: "read", db: "local" }
]
})
- 赋予权限:
db.grantRolesToUser("guance", [{role: "backup", actions: "find", db: "admin"}])
1.1.1. 以下两命令等价
db.runCommand(
{
listCollections: 1.0,
}
)
db.getCollectionNames()
加 filter:
db.runCommand(
{
listCollections: 1.0,
filter: <document>,
}
)
db.getCollectionNames().filter(function (c) { return c.indexOf('system.views') != 0; })
// 切换数据库
use myNewDatabase
// 插入一条数据
db.myCollection.insertOne( { x: 1 } );
// 查询 inventory 集合全部数据
db.inventory.find( {} )
// 查询 inventory 集合, status = "D"的文档数据
db.inventory.find( { status: "D" } )
1.2. 概念
SQL 术语/概念 | MongoDB 术语/概念 | 解释/说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | / | 表连接, MongoDB 不支持 |
primary key | primary key | 主键, MongoDB 自动将_id 字段设置为主键 |
通过下图实例, 我们也可以更直观的了解 Mongo 中的一些概念:
RDBMS 与 MongoDB 对应的术语:
RDBMS | MongoDB |
---|---|
数据库 | 数据库 |
表格 | 集合 |
行 | 文档 |
列 | 字段 |
表联合 | 嵌入文档 |
主键 | 主键 (MongoDB 提供了 key 为 _id ) |
数据库服务和客户端:
Mysqld/Oracle | mongodb |
---|---|
mysql/sqlplus | mongo |
1.3. 基础
1.3.1. 数据类型
数据类型 | 描述 |
---|---|
String | 字符串。存储数据常用的数据类型。在 MongoDB 中, UTF-8 编码的字符串才是合法的。 |
Integer | 整型数值。用于存储数值。根据你所采用的服务器, 可分为 32 位或 64 位。 |
Boolean | 布尔值。用于存储布尔值(真/假)。 |
Double | 双精度浮点值。用于存储浮点值。 |
Min/Max keys | 将一个值与 BSON(二进制的 JSON) 元素的最低值和最高值相对比。 |
Array | 用于将数组或列表或多个值存储为一个键。 |
Timestamp | 时间戳。记录文档修改或添加的具体时间。 |
Object | 用于内嵌文档。 |
Null | 用于创建空值。 |
Symbol | 符号。该数据类型基本上等同于字符串类型, 但不同的是, 它一般用于采用特殊符号类型的语言。 |
Date | 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间: 创建 Date 对象, 传入年月日信息。 |
Object ID | 对象 ID。用于创建文档的 ID。 |
Binary Data | 二进制数据。用于存储二进制数据。 |
Code | 代码类型。用于在文档中存储 JavaScript 代码。 |
Regular expression | 正则表达式类型。用于存储正则表达式。 |
1.3.2. 数据库
一个 MongoDB 中可以建立多个数据库。
MongoDB 的默认数据库为 db
, 该数据库存储在 data
目录中。
MongoDB 的单个实例可以容纳多个独立的数据库, 每一个都有自己的集合和权限, 不同的数据库也放置在不同的文件中。
有一些数据库名是保留的, 可以直接访问这些有特殊作用的数据库。
admin
: 从权限的角度来看, 这是 “root” 数据库。要是将一个用户添加到这个数据库, 这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行, 比如列出所有的数据库或者关闭服务器。local
: 这个数据永远不会被复制, 可以用来存储限于本地单台服务器的任意集合config
: 当 Mongo 用于分片设置时,config
数据库在内部使用, 用于保存分片的相关信息。
1.3.3. 文档 (Document)
文档是一组键值 (key-value) 对(即 BSON)。MongoDB 的文档不需要设置相同的字段, 并且相同的字段不需要相同的数据类型, 这与关系型数据库有很大的区别, 也是 MongoDB 非常突出的特点。
一个简单的文档例子如下:
{"site":"www.runoob.com", "name":"菜鸟教程"}
需要注意的是:
- 文档中的 键/值 对是有序的。
- 文档中的值不仅可以是在双引号里面的字符串, 还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
- MongoDB 区分类型和大小写。
- MongoDB 的文档不能有重复的键。
- 文档的键是字符串。除了少数例外情况, 键可以使用任意 UTF-8 字符。
- 文档键命名规范:
键不能含有 \0
(空字符)。这个字符用来表示键的结尾。
.
和$
有特别的意义, 只有在特定环境下才能使用。- 以下划线
_
开头的键是保留的(不是严格要求的)。
1.3.4. 集合
集合就是 MongoDB 文档组, 类似于 RDBMS(关系数据库管理系统: Relational Database Management System) 中的表格。
集合存在于数据库中, 集合没有固定的结构, 这意味着你在对集合可以插入不同格式和类型的数据, 但通常情况下我们插入集合的数据都会有一定的关联性。
比如, 我们可以将以下不同数据结构的文档插入到集合中:
{"site":"www.baidu.com"}
{"site":"www.google.com","name":"Google"}
{"site":"www.runoob.com","name":"菜鸟教程","num":5}
当第一个文档插入时, 集合就会被创建。
1.3.5. 合法的集合名
- 集合名不能是空字符串 “”。
- 集合名不能含有
\0
字符 (空字符), 这个字符表示集合名的结尾。 - 集合名不能以
system.
开头, 这是为系统集合保留的前缀。 - 用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含, 这是因为某些系统生成的集合中包含该字符。除非你要访问这种系统创建的集合, 否则千万不要在名字里出现
$
。
如下实例:
db.col.findOne()
1.3.6. 元数据
数据库的信息是存储在集合中。它们使用了系统的命名空间:
dbname.system.*
在 MongoDB 数据库中名字空间 <dbname>.system.*
是包含多种系统信息的特殊集合 (Collection), 如下:
集合命名空间 | 描述 |
---|---|
dbname.system.namespaces | 列出所有名字空间。 |
dbname.system.indexes | 列出所有索引。 |
dbname.system.profile | 包含数据库概要 (profile) 信息。 |
dbname.system.users | 列出所有可访问数据库的用户。 |
dbname.local.sources | 包含复制对端 (slave) 的服务器信息和状态。 |
1.4. JSON 与 BSON 区别
1.4.1. BSON
BSON 是由 10gen 开发的一个数据格式, 目前主要用于 MongoDB 中, 是 MongoDB 的数据存储格式。BSON 基于 JSON 格式, 选择 JSON 进行改造的原因主要是 JSON 的通用性及 JSON 的 schemaless 的特性。
按照定义性来说:
BSON( Binary Serialized Document Format) 是一种二进制形式的存储格式, 采用了类似于 C 语言结构体的名称、对表示方法, 支持内嵌的文档对象和数组对象, 具有轻量性、可遍历性、高效性的特点, 可以有效描述非结构化数据和结构化数据。
BSON 是一种类 JSON 的一种二进制形式的存储格式, 简称 Binary JSON, 它和 JSON 一样, 支持内嵌的文档对象和数组对象, 但是 BSON 有 JSON 没有的一些数据类型, 如 Date 和 BinData 类型。
BSON 可以做为网络数据交换的一种存储形式, 这个有点类似于 Google 的 Protocol Buffer, 但是 BSON 是一种 schema-less 的存储形式, 它的优点是灵活性高, 但它的缺点是空间利用率不是很理想。
总的来说, BSON 有三个特点: 轻量性、可遍历性、高效性。
1.4.2. JSON
JSON 是 JavaScript Object Notation 的首字母缩写, 单词的意思是 javascript 对象表示法, 这里说的 json 指的是类似于 javascript 对象的一种数据格式。
使用 JSON 的格式与解析方便的可以表示一个对象信息, json 有两种格式: ①对象格式: {“key1”:obj,“key2”:obj,“key3”:obj…}、②数组/集合格式: [obj,obj,obj…]。
- 更快的遍历速度
对 json 格式来说, 太大的 json 结构会导致数据遍历非常慢。在 json 中, 要跳过一个文档进行数据读取, 需要对此文档进行扫描才行, 需要进行麻烦的数据结构匹配, 比如括号的匹配。
而 BSON 对 json 的一大改进就是, 它会将 json 的每一个元素的长度存在元素的头部, 这样你只需要读取到元素长度就能直接 seek 到指定的点上进行读取了。
- 操作更简易
对 JSON 来说, 数据存储是无类型的, 比如你要修改基本一个值, 从 9 到 10, 由于从一个字符变成了两个, 所以可能其后面的所有内容都需要往后移一位才可以。
而使用 BSON, 你可以指定这个列为数字列, 那么无论数字从 9 长到 10 还是 100, 我们都只是在存储数字的那一位上进行修改, 不会导致数据总长变大。
当然, 在 mongoDB 中, 如果数字从整形增大到长整型, 还是会导致数据总长变大的。
- 增加了额外的数据类型
JSON 是一个很方便的数据交换格式, 但是其类型比较有限。
BSON 在其基础上增加了"byte array"数据类型。这使得二进制的存储不再需要先 base64 转换后再存成 JSON, 大大减少了计算开销和数据大小。
当然, 在有的时候, BSON 相对 JSON 来说也并没有空间上的优势, 比如对 {“field”:7}, 在 JSON 的存储上 7 只使用了一个字节, 而如果用 BSON, 那就是至少 4 个字节 (32 位)
目前在 10gen 的努力下, BSON 已经有了针对多种语言的编码解码包。并且都是 Apache 2 license 下开源的。并且还在随着 mongoDB 进一步地发展。
1.4.3. print bson
https://stackoverflow.com/questions/48913850/how-to-view-mgos-bson-raw-in-pretty-text
https://www.mongodb.com/community/forums/t/pretty-print-golang-pipelines/213173
https://www.mongodb.com/docs/drivers/go/current/fundamentals/bson/
https://pkg.go.dev/github.com/sbunce/bson
1.5. JS
1.5.1. docker /docker-entrypoint-initdb.d
运行的脚本
创建用户并赋予权限
adb = db.getSiblingDB("admin")
adb.auth("root", "example");
adb.createUser({
"user": "datakit",
"pwd": "123456",
"roles": [
{ role: "read", db: "admin" },
{ role: "clusterMonitor", db: "admin" },
{ role: "backup", db: "admin" },
{ role: "read", db: "local" }
]
});
1.5.2. 打开新的连接
在 mongo 命令行或者 JavaScript 文件中, 你可以通过 Mongo()
构造函数来创建一个数据库实例。
new Mongo()
new Mongo(<host>)
new Mongo(<host:port>)
以下示例是以 MongoDB 在 dashidan.com
默认端口运行, 并且将全局数据库变量设置为 myDatabase
, 可以通过 getDB()
方法获取一个新的连接实例:
conn = new Mongo();
db = conn.getDB("myDatabase");
如果 Mongodb 连接实例设置了访问控制, 你可以通过使用 db.auth()
方法来认证。
另外, 你可以通过 connect()
方法链接 MongoDB 实例。以下为连接到 MongoDB 绑定 dashidan.com
非默认端口 27020
的示例:
db = connect("dashidan.com:27020/myDatabase");
1.5.3. 命令输入和通过 mongo 脚本操作的区别
当你写 mongo 脚本的时候, 你需要考虑以下几点:
- 设置全局
db
变量, 可以通过getDB()
方法或者connect()
方法, 你可以将这个数据库引用设置给其他变量。 - Write operations in the mongo shell use a write concern of { w: 1 } by default. If performing bulk operations, use the Bulk() methods. See Write Method Acknowledgements for more information. Changed in version 2.6: Before MongoDB 2.6, call db.getLastError() explicitly to wait for the result of write operations.
- 你无法在 JavaScript 文件中使用任何命令行帮助, (例如: use , show dbs, etc.) 因为 JavaScript 中不支持。以下为常用命令行帮助有 JavaScript 对照表:
命令行帮助 | JavaScript |
---|---|
show dbs | show databases |
db.adminCommand(‘listDatabases’) | use db = db.getSiblingDB(’ ') |
show collections | db.getCollectionNames() |
show users | db.getUsers() |
show roles | db.getRoles({showBuiltinRoles: true}) |
show log | db.adminCommand({ ‘getLog’ : ’ ’ }) |
show logs | db.adminCommand({ ‘getLog’ : ‘*’ }) itcursor = db.collection.find() if ( cursor.hasNext() ){ cursor.next(); } |
- 在命令行交互模式中 mongo 将所有的结果打印出来。在 JavaScript 脚本中使用
print()
或者printjson()
方法来返回 JSON 格式。例: 在 JavaScript 中打印全部结果:
cursor = db.collection.find();
while ( cursor.hasNext() ) {
printjson( cursor.next() );
}
1.5.4. 写脚本
- 在系统命令行中, 使用
mongo
来使用 JavaScript. --eval
选项
使用 --eval
选项来传入 JavaScript 脚本:
mongo test --eval "printjson(db.getCollectionNames())"
这个命令连接运行在本机, 绑定 27017
端口的 mongo 实例, 并将 db.getCollectionNames()
方法的输出返回。
- 执行 JavaScript 文件
你可以直指定定一个以 .js
为后缀的 JavaScript 文件, mongo 可以直接执行。例如:
mongo dashidan.com:27017/test myjsfile.js
这个命令连接运行在 dashidan.com
, 绑定 27017
端口的 mongo 实例, 并将 myjsfile.js
的运行结果返回。
另外, 你可以在 JavaScript 文件中通过 Mongo()
构造函数来执行 mongodb
连接参数。参考 connect() 查看更多信息。
在 mongo 命令行中你可以通过 load()
方法运行 .js
文件, 例如:
load("myjstest.js")
这个方法加载并执行 myjstest.js
文件。
load()
方法接受相对路径和绝对路径, 默认为相对路径。使用绝对路径的例子:
load("scripts/myjstest.js")
load("/data/db/scripts/myjstest.js")
load()
方法中路径没有自动查找功能
如果当前路径和绝对路径都找不到文件, 则改脚本不会执行。
参考文章:
1.6. 问题解决
1.6.1. ERROR: child process failed, exited with 51
warning: initdb logs cannot write to '/proc/1/fd/1', so they are in '/data/db/docker-initdb.log' instead
about to fork child process, waiting until server is ready for connections.
forked process: 30
ERROR: child process failed, exited with 51
To see additional information in this output, start without the "--fork" option.
解决方案:
warning: initdb logs cannot write to '/proc/1/fd/1', so they are in '/data/db/docker-initdb.log' instead
cat /data/db/docker-initdb.log
1.6.2. “std::exception::what(): Operation not permitted\nActual exception type: std::system_error\n\n”
docker run -it mongo:6.0 /bin/bash
docker run -it mongo:6.0 --env MONGO_INITDB_ROOT_USERNAME=root --env MONGO_INITDB_ROOT_PASSWORD=example /usr/local/bin/docker-entrypoint.sh
docker run -e MONGO_INITDB_ROOT_USERNAME=root -e MONGO_INITDB_ROOT_PASSWORD=example -it mongo:6.0 /bin/bash
docker run -e MONGO_INITDB_ROOT_USERNAME=root -e MONGO_INITDB_ROOT_PASSWORD=example -v /tmp/123:/data/db -it mongo:6.0
docker run -e MONGO_INITDB_ROOT_USERNAME=root -e MONGO_INITDB_ROOT_PASSWORD=example -it mongo:6.0 /usr/local/bin/docker-entrypoint.sh mongod
解决方案: 升级 docker 版本为 23.01
。原因未知, 参考自 这里。
另附上其它方案(没测试):
使用 docker 的数据卷 (Volume) 作为保存持久化数据的目录, 数据卷 Volume 可理解为虚拟磁盘。
- 创建 Volume 虚拟磁盘:
docker volume create --name <名称>
- 删除 Volume 虚拟磁盘:
docker volume rm <名称>
docker volume create --name mongodata
docker run --name mongodb -v mongodata:/data/db -p 27017:27017 -d mongo:latest
2. MongoDB: Create User – For Database, Admin, Root
In MongoDB, users can have privileges across different databases.
In the following article i will show how to create, show and delete a user in MongoDB.
I will also show how to create a user with admin
and a user with root
(superuser) privileges on the all databases in MongoDB.
2.1. Create a User in MongoDB
Authentication Database: In MongoDB, user can have privileges across different databases. When adding a user, you create the user in a specific database. This database is the authentication database for this user.
Connect to MongoDB using mongo shell:
$ mongo
2.2. Create Admin/Root User in MongoDB
Switch to admin database:
> use admin
Admin vs Root: The role
userAdminAnyDatabase
in MongoDB gives ability to create users and assign roles to them, but by itself it doesn’t allow the user to do anything else. The superuser role in MongoDB is theroot
.
Create mongo-admin
user:
> db.createUser(
{
user: "mongo-admin",
pwd: "passw0rd",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
}
)
Create mongo-root
user:
> db.createUser(
{
user: "mongo-root",
pwd: "passw0rd",
roles: [ { role: "root", db: "admin" } ]
}
)
2.3. Create User For Database
Switch to the database in which you would like to create a common user:
> use my-database
Create my-user
with readWrite permissions on my-database
:
> db.createUser(
{
user: "my-user",
pwd: "passw0rd",
roles: [ { role: "readWrite", db: "my-database" } ]
}
)
You can also create a user with different permissions on different databases.
For example, you can create my-user
and grant him readWrite permissions on my-database
and read permissions on another-database
:
> db.createUser(
{
user: "my-user",
pwd: "passw0rd",
roles: [
{ role: "readWrite", db: "my-database" },
{ role: "read", db:"another-database" }
]
}
)
Read more about built-in roles in the official documentation
.
2.4. Show Users in MongoDB
Show users in the current database:
> db.getUsers()
# - or -
> show users
2.5. Delete User in MongoDB
Delete a user from the current database:
> db.dropUser("my-user")
3. MongoDB 开发笔记
3.1. 报错: error decoding key dur.journaledMB: float64 can only be truncated to an integer type when truncation is enabled
以上报错是结构体里面的 journaledMB
反序列化的时候报的错误, 常见于需要获取的字段类型与获取到的不符, 需要截断, 只能在启用截断时截断为整数类型, 所以有了上述提醒。
解决方案: 可以在 bson tag 追加 ,truncate
, 如下所示:
JournaledMB int64 `bson:"journaledMB,truncate"`