第20单元 改善文档存储:MongoDB
文档存储(即一个NoSQL数据库)是一个具有属性的对象(通常称为文档)的非易失性集合。目前,人们已经开发了许多不同的文档存储的实现方案。本单元重点分析其中一种实现方案——MongoDB,并简要介绍其最主要的竞争对手CouchDB2。
MongoDB是一个非关系型数据库。一个MongoDB服务器可以支持多个不相关的数据库。数据库由一个或多个文档集合组成,集合中的所有文档都有唯一的标识符。
在Python中,我们用pymongo模块中MongoClient类的实例来实现MongoDB客户端。可以创建一个无参数的客户端(适用于典型的安装了本地服务器的情况),也可以用服务器的主机名和端口号作为参数创建客户端,或使用服务器的统一资源标识符(URI)作为参数创建客户端:
import pymongo as mongo # 使用默认的初始化方式 client1 = mongo.MongoClient() # 指定主机和端口号 client2 = mongo.MongoClient("localhost", 27017) # 用URI方式指定主机和端口号 client3 = mongo.MongoClient("mongodb://localhost:27017/")
客户一旦端建立了与数据库服务器的连接,就可以选择当前激活的数据库,进而选择激活的集合。您可以使用面向对象(“点”)或字典样式的符号。如果所选的数据库或集合不存在,服务器会立即创建它们:
# 创建并选择活动数据库的两种方法 db = client1.dsdb db = client1["dsdb"] # 创建并选择活动集合的两种方法 people = db.people people = db["people"]
pymongo模块用字典变量来表示MongoDB文档。表示对象的每个字典必须具有_id这个键。如果该键不存在,服务器会自动生成它。
集合对象提供用于在文档集合中插入、搜索、删除、更新、替换和聚合文档以及创建索引的功能。
函数insert_one(doc)和insert_many(docs)将文档或文档列表插入集合。它们分别返回对象InsertOneResult或InsertManyResult,这两个对象分别提供inserted_id和inserted_ids属性。当文档没有明确的键时,就需要使用这些属性来找出文档的键。如果指定了_id键,则在执行插入操作后,该键值也不会改变:
person1 = {"empname" : "John Smith", "dob" : "1957-12-24"} person2 = {"_id" : "XVT162", "empname" : "Jane Doe", "dob" : "1964-05-16"} person_id1 = people.insert_one(person1).inserted_id ➾ ObjectId('5691a8720f759d05092d311b') # 注意出现了一个新的名为“_id”的键! person1 ➾ {'empname': 'John Smith', 'dob': '1957-12-24', ➾ '_id': ObjectId('5691a8720f759d05092d311b')} person_id2 = people.insert_one(person2).inserted_id ➾ "XVT162" persons = [{"empname" : "Abe Lincoln", "dob" : "1809-02-12"}, {"empname" : "Anon I. Muss"}] result = people.insert_many(persons) result.inserted_ids ➾ [ObjectId('5691a9900f759d05092d311c'), ➾ ObjectId('5691a9900f759d05092d311d')]
函数find_one()和find()给出匹配可选属性的一个或多个文档,其中find_one()返回文档,而find()返回一个游标(一个生成器),可以使用list()函数将该游标转换为列表,或者在for循环中将其用作迭代器。如果将字典作为参数传递给这些函数中的任意一个,函数将给出与字典的所有键值相等的文档:
everyone = people.find() list(everyone) ➾ [{'empname': 'John Smith', 'dob': '1957-12-24', ➾ '_id': ObjectId('5691a8720f759d05092d311b')}, ➾ {'empname': 'Jane Doe', 'dob': '1964-05-16', '_id': 'XVT162'}, ➾ {'empname': 'Abe Lincoln', 'dob': '1809-02-12', ➾ '_id': ObjectId('5691a9900f759d05092d311c')}, ➾ {'empname': 'Anon I. Muss', '_id': ObjectId('5691a9900f759d05092d311d')}] list(people.find({"dob" : "1957-12-24"})) ➾ [{'empname': 'John Smith', 'dob': '1957-12-24', ➾ '_id': ObjectId('5691a8720f759d05092d311b')}] people.find_one() ➾ [{'empname': 'John Smith', 'dob': '1957-12-24', ➾ '_id': ObjectId('5691a8720f759d05092d311b')}] people.find_one({"empname" : "Abe Lincoln"}) ➾ {'empname': 'Abe Lincoln', 'dob': '1809-02-12', ➾ '_id': ObjectId('5691a9900f759d05092d311c')} people.find_one({"_id" : "XVT162"}) ➾ {'empname': 'Jane Doe', 'dob': '1964-05-16', '_id': 'XVT162'}
下面介绍几个实现数据聚合和排序的分组和排序函数。函数sort()对查询的结果进行排序。当以无参数的方式调用它时,该函数按键_id的升序进行排序。函数count()返回查询结果中或整个集合中的文档数量:
people.count() ➾ 4 people.find({"dob": "1957-12-24"}).count() ➾ 1 people.find().sort("dob") ➾ [{'empname': 'Anon I. Muss', '_id': ObjectId('5691a9900f759d05092d311d')}, ➾ {'empname': 'Abe Lincoln', 'dob': '1809-02-12', ➾ '_id': ObjectId('5691a9900f759d05092d311c')}, ➾ {'empname': 'John Smith', 'dob': '1957-12-24', ➾ '_id': ObjectId('5691a8720f759d05092d311b')}, ➾ {'empname': 'Jane Doe', 'dob': '1964-05-16', '_id': 'XVT162'}]
函数delete_one(doc)和delete_many(docs)从集合中删除字典doc所标识的一个或多个文档。如果要在删除所有文档的同时保留集合,需使用空字典作为参数调用函数delete_many({}):
result = people.delete_many({"dob" : "1957-12-24"}) result.deleted_count ➾ 1
CouchDB
CouchDB是另外一个流行的NoSQL数据库。与MongoDB不同,CouchDB更侧重于可用性而非一致性。对于复制的CouchDB数据库(在多台计算机上运行),所有用户都可以使用它,但却不能保证不同的用户得到的文档是相同的。而对于复制的MongoDB,用户得到的一定是完全相同的文档,但是某些用户可能会无法使用数据库。如果实际使用中不复制数据库,那究竟是采用CouchDB还是MongoDB,就完全取决于个人喜好了。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论