pymongo支持MongoDB 2.6, 3.0, 3.2, 3.4, 3.6 and 4.0.
使用PyMongo的第一步是创建一个MongoClient来运行mongod实例。很简单
from pymongo import MongoClient
client = MongoClient()
上述代码采用默认host和port,我们也可以制定host和port,例如:
client = MongoClient('localhost', 27017)
或者采用MongoDB URL格式:
client = MongoClient('mongodb://localhost:27017/')
一个MongoDB实例可以支持多种独立数据库,当使用pymongo你可以用针对MongoClient实例采用属性风格连接到数据库:
db = client.test_database
如果你的数据库名字是这样的(例如test-database
),导致无法采用属性方式连接,可以采用字典方式连接:
db = client['test-database']
Collection是存储在MongoDB中的一组文档,可以粗略的理解为关系型数据库中的table,在pymongo中实现连接方式与获取数据库一样:
collection = db.test_collection
# or
collection = db['test-collection']
MongoDB
中关于collections
和database
有个重要特点:他们都是lazily创建的,上述所有命令都不会对服务器产生实际操作。
只有在第一个document
被嵌入后,Collections
和databases
才会被创建。
MongoDB中的数据采用类JSON格式存储或表示。在PyMongo中我们用字典表示documents。例如下面的字典可以用来表示一个博客帖子:
import datetime
post = {'author': 'Mike',
'text': 'My first blog post',
'tags': ['Mongodb', 'python', 'pymongo'],
'date': datetime.datetime.utcnow()}
documents
可以含有原生Python类型(例如datetime.datetime
实例),他们可以自动转化为对应的BSON
类型。
用insert_one()
方法将一个document
嵌入到collection
中。
posts = db.posts
post_id = posts.insert_one(post).inserted_id
当一个document被嵌入,如果document不含有‘_id
’,则一个特定的’_id
‘就自动添加。’_id
‘的值在整个collection中必须是独一无二的。 insert_one()
返回一个InsertOneResult
实例。关于’_id
'的更多信息,参见 documentation on _id.
嵌入第一个document之后,posts这个collection就存在在服务器上了。可以从过列出database上的所有collections来确认:
db.list_collection_names()
find_one()
获取一个单独的DocumentMongoDB中可执行的最简单的查询(query)就是 find_one()
. 这个方法返回一个满足条件的单一document(如果没有匹配的就返回None)。在你知道只有一个符合项或只关心第一个符合项的时候,这个方法是很有用的。如下,我们采用 find_one()
从posts这个collection中获取第一个document:
import pprint
pprint.pprint(posts.find_one())
结果是符合条件的我们先前插入的字典。
返回的document包含一个’_id
’,也就是在嵌入时候自动添加的那个。
find_one()也支持特定元素查询,限定满足author是“Mike”的结果:
pprint.pprint(posts.find_one({'author':'Mike'}))
如果我们尝试去找另一个作者’Eliot’,没有结果。
我们也可以通过他的’_id’来找一个post,在我们的例子中是ObjectId:
post_id
pprint.pprint(posts.find_one({'_id': post_id}))
一个ObjectId跟它的字符串表示是不一样的,比如:
post_id_as_str = str(post_id)
posts.find_one({'_id': post_id_as_str}) # No Result
在Web应用中一个常见的任务是从请求URL中获取一个ObjectId
,并找到对应的document
。在这个案例中,在将其传递为find_one
之前把string
转变为ObjectId
是很有必要的。
from bson.objectid import ObjectId
# web framework从URl中获取post_id并将其转为string
def get(post_id):
# 从string转为ObjectId
document = client.db.collection.find_one({'_id': ObjectId(post_id)})
通过一个查询语句获取多个document
,采用find()
方法。find()
返回一个Cursor
实例,它可以让我们迭代所有符合的documents。例如,我们可以迭代posts collection
中的每个document
:
for post in posts.find():
pprint.pprint(post)
跟find_one()
一样,我们可以给find()
传递一个document
来限制返回结果。这里,我们只能得到author是'Mike'
的那些documents
:
for post in posts.find({'author': 'Mike'}):
pprint.pprint(post)
MongoDB支持多种类型的高级搜索( advanced queries),例如,我们执行某个查询:限定晚于某一特定时期的的帖子,同时将结果按author排序:
d = datetime.datetime(2009, 11, 12, 12)
for post in posts.find({'date': {'$lt':d}}).sort('author'):
pprint.pprint(post)
这里我们采用一个特殊运算符'$lt'
来做范围查询,同时调用sort()
来对结果按照author
排序。
你可能也留意到了,我们存储的正规Python字符串与从服务器上恢复的字符串看起来不太一样(比如用u'Mike'
代替了’Mike'
).
MongoDB采用BSON格式存储数据,BSON字符串是UTF-8编码,所以PyMondo必须确保它存储的任何字符串只包含合法的UTF-8数据。正规字符串(<type ‘str’>)被验证并原样存储。首先Unicode字符串(<type ‘unicode’>)被编码成UTF-8.在我们的案例中,Python里的’Mike’被替换为u’Mike’的原因是PyMongo将每一个BSON字符串解码为unicode字符串,而非标准字符串。
为了让查询变得更有趣,让我们插入更多documents。除了可以插入单个document,也可以通过传递一个list作为insert_many()的第一个参数,实现bulk insert
(批量插入)操作。此操作会将list中的每个document都插入数据库,只需要想服务器发送一个命令:
new_posts = [{'author': 'Mike',
"text": "Another post!",
"tags": ["bulk", "insert"],
"date": datetime.datetime(2009, 11, 12, 11, 14)},
{"author": "Eliot",
"title": "MongoDB is fun",
"text": "and pretty easy too!",
"date": datetime.datetime(2009, 11, 10, 10, 45)}]
result = posts.insert_many(new_posts)
result.inserted_ids
关于上例,有两个有趣的地方:
tags
‘却有’title
’,这就是我们所说的MongDb是模式自由的(Schema-free)如果我们知识想要知道符合查询条件的结果一共有多少,可以采用count_documents()操作,而不用全部查出来。
posts.count_documents({})
或者只计算那些福特特定查询条件的:
posts.count_documents({'author':'Mike'})
增加索引可以加速特定查询,同时为查询和存储documents增加功能。在这个案例中,我们展示如何创建唯一索引( unique index),拒绝在索引值已存在于索引中的documents。
result = db.profiles.create_index([('user_id', pymongo.ASCENDING)],
unique = True)
sorted(list(db.profiles.index_information()))
现在有两个索引,一个是MongoDb自动船舰的'_id'
,另一个是刚才创建的’user_id
’。
user_profiles = [{'user_id': 211, 'name': 'Luke'},
{'user_id': 212, 'name': 'Ziltoid'}]
result = db.profiles.insert_many(user_profiles)
>>> new_profile = {'user_id': 213, 'name': 'Drew'}
>>> duplicate_profile = {'user_id': 212, 'name': 'Tommy'}
>>> result = db.profiles.insert_one(new_profile) # This is fine.
>>> result = db.profiles.insert_one(duplicate_profile)
Traceback (most recent call last):
DuplicateKeyError: E11000 duplicate key error index: test_database.profiles.$user_id_1 dup key: { : 212 }