MongoDB 笔记

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 术语/概念解释/说明
databasedatabase数据库
tablecollection数据库表/集合
rowdocument数据记录行/文档
columnfield数据字段/域
indexindex索引
table joins/表连接, MongoDB 不支持
primary keyprimary key主键, MongoDB 自动将_id 字段设置为主键

通过下图实例, 我们也可以更直观的了解 Mongo 中的一些概念:

1.png

RDBMS 与 MongoDB 对应的术语:

RDBMSMongoDB
数据库数据库
表格集合
文档
字段
表联合嵌入文档
主键主键 (MongoDB 提供了 key 为 _id )

数据库服务和客户端:

Mysqld/Oraclemongodb
mysql/sqlplusmongo

1.3. 基础

MongoDB 概念解析

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…]。

  1. 更快的遍历速度

对 json 格式来说, 太大的 json 结构会导致数据遍历非常慢。在 json 中, 要跳过一个文档进行数据读取, 需要对此文档进行扫描才行, 需要进行麻烦的数据结构匹配, 比如括号的匹配。

而 BSON 对 json 的一大改进就是, 它会将 json 的每一个元素的长度存在元素的头部, 这样你只需要读取到元素长度就能直接 seek 到指定的点上进行读取了。

  1. 操作更简易

对 JSON 来说, 数据存储是无类型的, 比如你要修改基本一个值, 从 9 到 10, 由于从一个字符变成了两个, 所以可能其后面的所有内容都需要往后移一位才可以。

而使用 BSON, 你可以指定这个列为数字列, 那么无论数字从 9 长到 10 还是 100, 我们都只是在存储数字的那一位上进行修改, 不会导致数据总长变大。

当然, 在 mongoDB 中, 如果数字从整形增大到长整型, 还是会导致数据总长变大的。

  1. 增加了额外的数据类型

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 dbsshow databases
db.adminCommand(‘listDatabases’)use db = db.getSiblingDB(’ ')
show collectionsdb.getCollectionNames()
show usersdb.getUsers()
show rolesdb.getRoles({showBuiltinRoles: true})
show logdb.adminCommand({ ‘getLog’ : ’ ’ })
show logsdb.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 the root.

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"`
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云满笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值