MongoDB概述

MongoDB简介

MongoDB是2009年问世的一个面向文档的数据库管理系统,由C++语言编写,旨在为Web应用提供可扩展的高性能数据存储解决方案。虽然在划分类别的时候后,MongoDB被认为是NoSQL的产品,但是它更像一个介于关系数据库和非关系数据库之间的产品,在非关系数据库中它功能最丰富,最像关系数据库。

MongoDB将数据存储为一个文档,一个文档由一系列的“键值对”组成,其文档类似于JSON对象,但是MongoDB对JSON进行了二进制处理(能够更快的定位key和value),因此其文档的存储格式称为BSON。关于JSON和BSON的差别大家可以看看MongoDB官方网站的文章《JSON and BSON》

目前,MongoDB已经提供了对Windows、macOS、Linux、Solaris等多个平台的支持,而且也提供了多种开发语言的驱动程序,Python当然是其中之一。

MongoDB的安装和启动

可以从MongoDB的官方下载链接下载MongoDB,官方提供了Windows、macOS和多种Linux版本的安装包。下面以CentOS为例,简单说一下如何安装和启动MongoDB。

下载服务器和命令行的RPM安装包。

  1. wget https://repo.mongodb.org/yum/redhat/7/mongodb-org/4.4/x86_64/RPMS/mongodb-org-server-4.4.2-1.el7.x86_64.rpm
  2. rpm -ivh mongodb-org-server-4.4.2-1.el7.x86_64.rpm
  3. wget https://repo.mongodb.org/yum/redhat/7/mongodb-org/4.4/x86_64/RPMS/mongodb-org-shell-4.4.2-1.el7.x86_64.rpm
  4. rpm -ivh mongodb-org-shell-4.4.2-1.el7.x86_64.rpm

启动MongoDB服务器,需要先创建保存数据的文件夹。

  1. mkdir -p /data/db

修改MongoDB的配置文件,将其中bindIp选项的值修改为本机IP地址而不是默认的127.0.0.1,本机IP地址可以通过ifconfig命令进行查看。

  1. vim /etc/mongod.conf

使用systemctl命令启动服务。

  1. systemctl start mongod

MongoDB基本概念

我们通过与关系型数据库的比较来说明MongoDB中的一些概念。

SQL MongoDB
database database
table(表) collection(集合)
row(行) document(文档)
column(列) field(字段)
index index
table joins(表连接) (嵌套文档)
primary key primary key

通过Shell操作MongoDB

  1. 启动命令行工具,进入交互式环境。

    1. mongo

    说明

  2. 查看、创建和删除数据库。

    1. > // 显示所有数据库
    2. > show dbs
    3. admin 0.000GB
    4. config 0.000GB
    5. local 0.000GB
    6. > // 创建并切换到school数据库
    7. > use school
    8. switched to db school
    9. > // 删除当前数据库
    10. > db.dropDatabase()
    11. { "ok" : 1 }
  3. 创建、删除和查看集合。

    1. > // 创建并切换到school数据库
    2. > use school
    3. switched to db school
    4. > // 创建colleges集合
    5. > db.createCollection('colleges')
    6. { "ok" : 1 }
    7. > // 创建students集合
    8. > db.createCollection('students')
    9. { "ok" : 1 }
    10. > // 查看所有集合
    11. > show collections
    12. colleges
    13. students
    14. > // 删除colleges集合
    15. > db.colleges.drop()
    16. true

    说明:在MongoDB中插入文档时如果集合不存在会自动创建集合,所以也可以按照下面的方式通过插入文档来创建集合。

  4. 文档的CRUD操作。

    1. > // 向students集合插入文档
    2. > db.students.insert({stuid: 1001, name: '骆昊', age: 40})
    3. WriteResult({ "nInserted" : 1 })
    4. > // 向students集合插入文档
    5. > db.students.save({stuid: 1002, name: '王大锤', tel: '13012345678', gender: '男'})
    6. WriteResult({ "nInserted" : 1 })
    7. > // 查看所有文档
    8. > db.students.find()
    9. { "_id" : ObjectId("5b13c72e006ad854460ee70b"), "stuid" : 1001, "name" : "骆昊", "age" : 38 }
    10. { "_id" : ObjectId("5b13c790006ad854460ee70c"), "stuid" : 1002, "name" : "王大锤", "tel" : "13012345678", "gender" : "男" }
    11. > // 更新stuid为1001的文档
    12. > db.students.update({stuid: 1001}, {'$set': {tel: '13566778899', gender: '男'}})
    13. WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    14. > // 插入或更新stuid为1003的文档
    15. > db.students.update({stuid: 1003}, {'$set': {name: '白元芳', tel: '13022223333', gender: '男'}}, upsert=true)
    16. WriteResult({
    17. "nMatched" : 0,
    18. "nUpserted" : 1,
    19. "nModified" : 0,
    20. "_id" : ObjectId("5b13c92dd185894d7283efab")
    21. })
    22. > // 查询所有文档
    23. > db.students.find().pretty()
    24. {
    25. "_id" : ObjectId("5b13c72e006ad854460ee70b"),
    26. "stuid" : 1001,
    27. "name" : "骆昊",
    28. "age" : 38,
    29. "gender" : "男",
    30. "tel" : "13566778899"
    31. }
    32. {
    33. "_id" : ObjectId("5b13c790006ad854460ee70c"),
    34. "stuid" : 1002,
    35. "name" : "王大锤",
    36. "tel" : "13012345678",
    37. "gender" : "男"
    38. }
    39. {
    40. "_id" : ObjectId("5b13c92dd185894d7283efab"),
    41. "stuid" : 1003,
    42. "gender" : "男",
    43. "name" : "白元芳",
    44. "tel" : "13022223333"
    45. }
    46. > // 查询stuid大于1001的文档
    47. > db.students.find({stuid: {'$gt': 1001}}).pretty()
    48. {
    49. "_id" : ObjectId("5b13c790006ad854460ee70c"),
    50. "stuid" : 1002,
    51. "name" : "王大锤",
    52. "tel" : "13012345678",
    53. "gender" : "男"
    54. }
    55. {
    56. "_id" : ObjectId("5b13c92dd185894d7283efab"),
    57. "stuid" : 1003,
    58. "gender" : "男",
    59. "name" : "白元芳",
    60. "tel" : "13022223333"
    61. }
    62. > // 查询stuid大于1001的文档只显示name和tel字段
    63. > db.students.find({stuid: {'$gt': 1001}}, {_id: 0, name: 1, tel: 1}).pretty()
    64. { "name" : "王大锤", "tel" : "13012345678" }
    65. { "name" : "白元芳", "tel" : "13022223333" }
    66. > // 查询name为“骆昊”或者tel为“13022223333”的文档
    67. > db.students.find({'$or': [{name: '骆昊'}, {tel: '13022223333'}]}, {_id: 0, name: 1, tel: 1}).pretty()
    68. { "name" : "骆昊", "tel" : "13566778899" }
    69. { "name" : "白元芳", "tel" : "13022223333" }
    70. > // 查询学生文档跳过第1条文档只查1条文档
    71. > db.students.find().skip(1).limit(1).pretty()
    72. {
    73. "_id" : ObjectId("5b13c790006ad854460ee70c"),
    74. "stuid" : 1002,
    75. "name" : "王大锤",
    76. "tel" : "13012345678",
    77. "gender" : "男"
    78. }
    79. > // 对查询结果进行排序(1表示升序,-1表示降序)
    80. > db.students.find({}, {_id: 0, stuid: 1, name: 1}).sort({stuid: -1})
    81. { "stuid" : 1003, "name" : "白元芳" }
    82. { "stuid" : 1002, "name" : "王大锤" }
    83. { "stuid" : 1001, "name" : "骆昊" }
    84. > // 在指定的一个或多个字段上创建索引
    85. > db.students.ensureIndex({name: 1})
    86. {
    87. "createdCollectionAutomatically" : false,
    88. "numIndexesBefore" : 1,
    89. "numIndexesAfter" : 2,
    90. "ok" : 1
    91. }

使用MongoDB可以非常方便的配置数据复制,通过冗余数据来实现数据的高可用以及灾难恢复,也可以通过数据分片来应对数据量迅速增长的需求。关于MongoDB更多的操作可以查阅官方文档 ,同时推荐大家阅读Kristina Chodorow写的《MongoDB权威指南》

在Python程序中操作MongoDB

可以通过pip安装pymongo来实现对MongoDB的操作。

  1. pip install pymongo

进入Python交互式环境,就可以执行以下的操作。

  1. >>> from pymongo import MongoClient
  2. >>>
  3. >>> client = MongoClient('mongodb://127.0.0.1:27017')
  4. >>> db = client.school
  5. >>> for student in db.students.find():
  6. ... print('学号:', student['stuid'])
  7. ... print('姓名:', student['name'])
  8. ... print('电话:', student['tel'])
  9. ...
  10. 学号: 1001.0
  11. 姓名: 骆昊
  12. 电话: 13566778899
  13. 学号: 1002.0
  14. 姓名: 王大锤
  15. 电话: 13012345678
  16. 学号: 1003.0
  17. 姓名: 白元芳
  18. 电话: 13022223333
  19. >>> db.students.find().count()
  20. 3
  21. >>> db.students.remove()
  22. {'n': 3, 'ok': 1.0}
  23. >>> db.students.find().count()
  24. 0
  25. >>> from pymongo import ASCENDING
  26. >>>
  27. >>> coll = db.students
  28. >>> coll.create_index([('name', ASCENDING)], unique=True)
  29. 'name_1'
  30. >>> coll.insert_one({'stuid': int(1001), 'name': '骆昊', 'gender': True})
  31. <pymongo.results.InsertOneResult object at 0x1050cc6c8>
  32. >>> coll.insert_many([{'stuid': int(1002), 'name': '王大锤', 'gender': False}, {'stuid': int(1003), 'name': '白元芳', 'gender': True}])
  33. <pymongo.results.InsertManyResult object at 0x1050cc8c8>
  34. >>> for student in coll.find({'gender': True}):
  35. ... print('学号:', student['stuid'])
  36. ... print('姓名:', student['name'])
  37. ... print('性别:', '男' if student['gender'] else '女')
  38. ...
  39. 学号: 1001
  40. 姓名: 骆昊
  41. 性别:
  42. 学号: 1003
  43. 姓名: 白元芳
  44. 性别:

关于pymongo更多的知识可以通过它的官方文档进行了解,也可以使用MongoEngine这样的库来简化Python程序对MongoDB的操作,除此之外,还有以异步I/O方式访问MongoDB的三方库motor都是不错的选择。