MongoDB 笔记


概述

MongoDB 是一个可扩展、高性能的 NoSQL 数据库,其主要面向文档存储,支持丰富的查询表达式,可轻松查询文档中的内存对象及数组,且支持使用 map/reduce 来对数据进行批量处理和聚合操作。

参考文档

  1. 官方使用手册
  2. SQL v.s. MongoDB
  3. MongoDB 入门与在线测试

关键知识点

  1. SQL中概念对比 MongoDB 中的概念
SQL MongoDB
database database
table collection
row document or BSON document
column field
index index

更多可参考参考文档 《2.SQL v.s. MongoDB 》 此处强烈建议,联系 SQL 来学习 MongoDB,可以起到事倍功半、举一反三的效果。

  1. 为什么要学习 MongoDB?

    • 区别于 sql 关系型数据库的 no-sql 数据库。此类数据库结构灵活,易于伸缩,而且天然支持 JSON 格式数据,可以支持极其复杂的数据格式,表示丰富的数据模型;
    • 查询/分析效率高,十分适用于分析;
    • BigQuery 导出的 GA 数据可以无缝入到 MongoDB 中
  2. MongoDB 安装

杂记

  1. 对于入库的 document, mongoDB 自动添加了一个 _id 字段
  2. 一个数据库中存储有多个集合 collections
  3. MongoDB 命名限制
    • 不允许包含以下字符:/\. "$*<>:|?
  4. 默认情况下,一个集合中,不要求其内部的文档拥有相同的格式。也就是说,单个集合中的文档不需要拥有相同的字段集,并且字段的数据类型可以在集合中的文档中有所不同。
    • 从 3.2 版本开始,可以在更新和插入操作期间强制执行一个集合的文档验证规则。
  5. mongoDB 中的视图和 sql 的性质相同,都是虚拟对象。
  6. mongoDB 支持的数据结构中,亦包含 array 格式和 embedded document 这种格式,所以 Bigquery 的数据架构应该是完全兼容的
  7. 字段中,_id 是保留字段。其值必须是唯一的,且不可变的(immutable)
  8. mongoDB 使用点表示法,来获取 array 中数据,例如 "<array>.<index>" 对于嵌入式文档则使用 "<embedded document>.<field>"
  9. 文档相关
    • 大小最大为 16mb
    • 排序上 _id 始终为第一个字段
  10. MongoDB 是最流行的 NoSQL 数据库系统
  11. MongoDB Ubuntun 中 db 目录默认在 /var/lib/mongodb 日志默认在 /var/log/mongodb
    • 默认情况下 mongodb 的安装会使用一个 mongodb 的账户(linux 用户,而且上述文件夹的所有人也是 mongodb)
    • 在 mongoDB 运行中修改了配置文件,则必须重启才能使配置文件生效
  12. 运行 mongoDB 社区版
    • 开启 monogoDB
      • sudo systemctl start mongod
    • 查看 mongoDB 状态
      • systemctl status mongod
    • 停止
      • systemctl stop mongod
    • 重启
      • systemctl restart mongod
    • 使用 mongoDB
      • mongo
  13. 查看系统所使用的初始化系统
    • ps --no-headers -o comm 1
      • systemd 对应使用 systemctl 命令
      • System V init 对应 service 命令
  14. mongoDB shell 是交互式 js 接口。
  15. mongoDB 数据插入
  16. 数据模型
    • mongoDB 文档没有强制的格式要求,虽然可以自己设置。
    • 引用:引用通过包含从一个文档到另一个文档的链接或引用来存储数据之间的关系。应用程序可以解析这些引用以访问相关数据。广义上讲,这些是规范化的数据模型。
      • 有点类似外键的感觉
  17. 索引
    • 索引支持在 MongoDB 中高效执行查询,没有索引,MongoDB 必须执行集合扫描,即扫描集合中的每个文档
    • MongoDB 在集合级别定义索引,并支持MongoDB集合中文档的任何字段或子字段的索引。
    • 索引创建后无法更名,只能重建
    • 索引类型
      • 单字段索引,对于单字段索引和排序操作,索引键的排序顺序(即升序或降序)无关紧要,因为MongoDB可以沿任一方向遍历索引。
      • 复合索引
      • 多键索引
  18. Avro 格式数据,是 Apache 中数据序列化格式数据。支持 Python
  19. MongoDB 更改字段类型
  20. MongoDB 配置远程访问
    • 查看端口占用情况 netstat -tunlp
      • 发现 mongodb 占用了端口 27017 tcp 0 0 127.0.0.1:27017 0.0.0.0:* LISTEN 1428/mongod
    • 可以设置 build_ip=0.0.0.0 属性到配置文件,以允许访问
    • 使用 MongoHub 链接远程服务器上 MongoDB
    • 流程:
    • 注意:记得查看防火墙,允许接口请求。
  21. MongoDB 用户权限管理
    • 流程:
        1. 进入 mongodb shell
          • mongo
        1. 切换数据库
          • use admin
        1. 创建 admin 超级管理员用户
          // 官方文档
          // https://docs.mongodb.com/manual/reference/method/db.createUser/index.html
          db.createUser(  
          { 
             user: "admin",  
             customData: {description:"superuser"},
             pwd: "****",  
             roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]  
          }  
          )
          // user字段,为新用户的名字;
          // pwd字段,用户的密码;
          // cusomData字段,为任意内容,例如可以为用户全名介绍;
          // roles字段,指定用户的角色,可以用一个空数组给新用户设定空角色。在roles字段,可以指定内置角色和用户定义的角色。
          // 超级用户的role有两种,userAdmin或者userAdminAnyDatabase(比前一种多加了对所有数据库的访问,仅仅是访问而已)。
          // db是指定数据库的名字,admin是管理数据库。
          // 不能用admin数据库中的用户登录其他数据库。注:只能查看当前数据库中的用户,哪怕当前数据库admin数据库,也只能查看admin数据库中创建的用户。
          
        1. 创建 root 超级用户
          db.createUser(
          {
             user:"root",
             pwd:"pwd",
             roles:["root"]
          }
          )
          
        1. 创建一个业务数据库管理员用户(只负责某个/某几个数据的CRUD)
          db.createUser({
          user:"****",
          pwd:"****",
          customData:{
             name:'****',
             email:'****@truemetrics.cn',
          },
          roles:[
             {role:"dbAdmin",db:"bigquery_transfer"},
          ]
          })
          
        1. 查看创建的用户
          • show users;
          • db.system.users.find()
          • db.runCommand({usersInfo:"chenfy"})
        1. 删除数据库用户
          • use admin;
          • db.dropUser('<usernamed>')
        1. 修改用户密码
          • admin 库中 db.changeUserPassword("admin", "****")
        1. 设置 mongodb 访问权限,要求必须使用密码登陆
          • 修改后的登陆方式
            • mongo --username **** -authenticationDatabase bigquery_transfer --password ****
            • mongo -u admin -authenticationDatabase admin -p ****
            • 注意,这块 userAdminAnyDatabase 这个权限,只能做到对数据库的管理,但是查询数据的时候就会报错显示不能。
        1. 查看当前用户
          • db.runCommand({connectionStatus : 1})
        1. 修改密码和用户信息
          db.runCommand(
          {
            updateUser:"****",
            roles:[
                {role:"readWrite",db:"bigquery_transfer"},
            ]
          }
          )
          
  22. MongoDB 访问权限控制
    • 创建用户的数据库(本例中为admin)是用户的身份验证数据库。尽管用户将对该数据库进行身份验证,但该用户可以在其他数据库中拥有角色;也就是说,用户的身份验证数据库并不限制用户的权限。
    • 设置配置文件 /etc/mongod.conf
      security:
        authorization: enabled
      • 设置完毕以后,权限设置生效。如果不设置这块的 authorization 前面的设置是无效的。
  23. Mongodb Built-In Roles
    • 的操作粒度截止到 db?所以对集合&集合内的数据,反而没有操作管理权限,要想允许写入,还是得 readWrite
    • dbOwner 可以对数据库执行任何管理角色。这个角色组合由授予的权限readWrite, dbAdmin和userAdmin角色。
    • 提供在当前数据库上创建和修改角色和用户的功能。由于该userAdmin角色允许用户向任何用户(包括他们自己)授予任何特权,因此该角色还间接提供了 对数据库或 集群(如果作用域为数据库)的超级用户访问权限admin。
  24. Java MongoDB SDK
  25. MongoDB 也可以通过 navicat 连接使用。

Commend

cmd

# 开启 shell
mongo

# 开启 Mongod
systemctl start mongod
# 状态查看
systemctl status mongod
# 停止
systemctl stop mongod
# 重启
systemctl restart mongod

Shell

-- 如果没有该 databases 则在首次存储数据时自动创建该 databases;
use myDB

-- 查看数据库
show databases;

-- 查看已创建的集合
show collections;

-- 创建集合
db.myNewCollection2.insertOne( { x: 1 } )
db.myNewCollection3.createIndex( { y: 1 } )

-- 显式创建集合
db.createCollection()

-- 查看 db 下集合名称
db.getCollectionNames()

-- 帮助
db.help()

-- 查看行数
db.ga_sessions.count()

-- 查询 特定 fullVisitorId
db.ga_sessions.find( {"fullVisitorId":"5485017567268822718"} )

-- 查询会话中 visitStartTime 小于 1501616585 的记录
db.ga_sessions.find( {"fullVisitorId": { "$lt" : 1501616585} } )
-- 这块有个问题,在于通过 json 格式导出时,没有保留整形格式。
-- 使用 JSON 格式导出数据时,INT64(整数)数据类型会编码为 JSON 字符串,以便在其他系统读取数据时保留 64 位精度。

db.ga_sessions.find( {"visitStartTime": "1501583974" } )

-- 创建索引
-- db.collection.createIndex( <key and index type specification>, <options> )
db.ga_sessions.createIndex( {"visitStartTime": -1 } )

-- 查询索引
db.ga_sessions.getIndexes()

Docker

docker pull mongo:4.2.12

pymongo

pip3 install pymongo
# https://pymongo.readthedocs.io/en/stable/tutorial.html
import pymongo

client = pymongo.MongoClient(
    host='101.37.68.59', 
    port=27017
    # 无设置访问权限时,可通过上述方式直接访问
   )
# or 101.37.68.59
client = pymongo.MongoClient('mongodb://101.37.68.59:27017/')
# 关于身份认证
client = pymongo.MongoClient('mongodb://101.37.68.59:27017/',
    username='<user-name>',
    password='<password>',
    authSource='<database-name>',
    authMechanism='SCRAM-SHA-1'
    # 关于 SCRAM-SHA-1 认证方式如下 https://pymongo.readthedocs.io/en/stable/examples/authentication.html#scram-sha-1-rfc-5802
)

client = pymongo.MongoClient('mongodb://101.37.68.59:27017/',
    username='****',
    password='****',
    authSource='****',
    authMechanism='SCRAM-SHA-1'
)

# 查看数据库
client.list_database_names()

db = client.bigquery_transfer
col = db.ga_sessions
col.estimated_document_count()
col.find_one( {"visitStartTime": "1501583974" } )

Java

<!-- pom.xml -->
<dependencies>
    <dependency>
        <groupId>org.mongodb</groupId>
        <artifactId>mongodb-driver-sync</artifactId>
        <version>4.2.0</version>
    </dependency>
</dependencies>
import com.mongodb.ConnectionString;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.MongoCollection;
import com.mongodb.MongoClientSettings;

// ...
ConnectionString connString = new ConnectionString(
    "mongodb://<user-name>:<password>@<host-nname>/?authSource=<database>&authMechanism=SCRAM-SHA-1"
);
MongoClientSettings settings = MongoClientSettings.builder()
    .applyConnectionString(connString)
    .retryWrites(true)
    .build();
// 建立客户端连接
MongoClient mongoClient = MongoClients.create(settings);
// 获得对应数据库对象
MongoDatabase database = mongoClient.getDatabase("****");
// 获得对应集合对象
MongoCollection<Document> coll = database.getCollection("****");

// 执行后续操作