君は春の中にいる、かけがえのない春の中にいる.

你驻足于春色中,于那独一无二的春色之中.

PyMongo官方文档翻译

最近做的几个项目都用到了Python+MongoDB,好像更新一版的Mongo刚刚发布。既然是使用python,肯定是绕不过Pymongo库了,先从官方文档看起。

想练习英语的戳这里~http://api.mongodb.org/python/current/tutorial.html

教程

本教程旨在介绍使用MongoDB和PyMongo

准备

安装PyMongo模块,MongoDB数据库。
恩,在python的shell里,下面这句话没报错就算安装成功了(废话~)

1
>>>import pymongo

本教程还假设MongoDB实例运行在默认的主机(127.0.0.1)和端口(27017)。假设您已经下载并安装MongoDB,您可以启动它就像这样:

1
$ mongod

使用MongoClient完成数据库连接

第一步就是使用PyMongo中的MongoClient来完成程序和数据库之间的连接

1
2
>>> from pymongo import MongoClient
>>> client = MongoClient()

上面的代码将在默认的主机和端口连接。我们也可以显式地指定主机和端口,如下:

1
>>> client = MongoClient('localhost', 27017)

也可以使用另一种形式:

1
>>> client = MongoClient('mongodb://localhost:27017/')

获得数据库

MongoDB的单个实例可以支持多个独立的数据库。PyMongo支持使用属性的形式来获得数据库:

1
>>> db = client.test_database

如果上面的形式无法访问到数据库,可以采用另一种字典的形式来访问:

1
>>> db = client['test-database']

获得集合

集合是MongoDB中存储的一组文档,可以类比为关系型数据库中的表,获得集合的方式与获得数据库方式相同

拥有两种方式:

1
2
>>> collection = db.test_collection
>>> collection = db['test-collection']

值得注意的是,集合和库在MongoDB中的创建是松散的,以上命令实际上并没有在服务器端做任何操作。

当有文档(数据)插入到里面的时候,集合和库才被创建。

文档(数据)

MongoDB中的数据使用(存储为)JSON格式文件。在PyMongo中使用字典来表示这种结构。

举个栗子,下面的字典可以用来代表一篇博文:

1
2
3
4
5
>>> import datetime
>>> post = {"author": "Mike",
... "text": "My first blog post!",
... "tags": ["mongodb", "python", "pymongo"],
... "date": datetime.datetime.utcnow()}

注意,文档可以包含本地Python类型(如datetime.datetime实例),这些会自动转换为合适的BSON类型。

插入文件

要插入一个文件到集合中,我们可以使用insert_one( )方法:

1
2
3
4
>>> posts = db.posts
>>> post_id = posts.insert_one(post).inserted_id
>>> post_id
ObjectId('...')

如果插入的文档没有“_id”这个键的话,系统会自动给它加上。“_id”键的值在整个集合中是唯一的(有点主键的意思)。insert _one( )返回一个InsertOneResult的实例。更多关于”_id“的信息,参阅 _id。

在插入第一个文档后,集合就真正在服务器上创建。通过列出库中所有的集合,我们可以验证这一点:

1
2
>>> db.collection_names(include_system_collections=False)
[u'posts']

通过find_one( )获取单个文档

最基本的可以执行的查询类型有find_one( )。这个方法根据查询返回一个匹配的文档。如果没有匹配就返回None。

对于只有单一匹配或者只对第一个匹配感兴趣的情况下,可以选用这种方法。下面是一个获取第一个文档的栗子~

1
2
>>> posts.find_one()
{u'date': datetime.datetime(...), u'text': u'My first blog post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'mongodb', u'python', u'pymongo']}

结果是我们之前插入的那个注意到返回结果中”_id”这个键是自动加入的。
find_one()也支持特定的结果匹配。比如我们用作者”Mike”来限制返回的查找结果

1
2
>>> posts.find_one({"author": "Mike"})
{u'date': datetime.datetime(...), u'text': u'My first blog post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'mongodb', u'python', u'pymongo']}

如果我们用另一个文档中不存在的字典“Eliot”来查找,将得不到结果:

1
2
>>> posts.find_one({"author": "Eliot"})
>>>

通过对象ID查询

我们也可以通过“_id”来查找

1
2
3
4
>>> post_id
ObjectId(...)
>>> posts.find_one({"_id": post_id})
{u'date': datetime.datetime(...), u'text': u'My first blog post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'mongodb', u'python', u'pymongo']}

注意,对象ID不是一个字符串

1
2
3
>>> post_id_as_str = str(post_id)
>>> posts.find_one({"_id": post_id_as_str}) # No result
>>>

web应用程序中的一个常见任务是从URL得到对象ID,找到匹配的文档。
这种情况下,需要将对象ID从字符串类型转换到ObjectId(符合find_one格式的类型):

1
2
3
4
5
from bson.objectid import ObjectId
# The web framework gets post_id from the URL and passes it as a string
def get(post_id):
# Convert from string to ObjectId:
document = client.db.collection.find_one({'_id': ObjectId(post_id)})

UNICODE字符串注意

你可能注意到,服务器中得到的数据和常规的Python字符串不太一样(例如用u’Mike’来代替’Mike’)

这是因为我们的数据库以BSON的格式存储数据。这种格式采用UTF-8编码,所以PyMongo需要确保所有

存储的字符串包含唯一可用的UTF-8数据。基于此,PyMongo解码每一个BSON字符为Python的unicode字符,而不是常见的字符串。

批量插入

为了使查询更加有趣,让我们插入更多的文档。

除了插入一个文档,我们也可以执行批量插入操作,
通过insert_many插入列表的方式,可以插入列表中的每一个文档,而只向服务器发送一次指令。

1
2
3
4
5
6
7
8
9
10
11
>>> 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
[ObjectId('...'), ObjectId('...')]

对于这个栗子,需要多去咀嚼的地方:

结果返回了两个对象ID实例,就是我们批量插入地文档;

两个文档的键并不一样哦,一个是“tags”,另一个是“title”,这就是我们之前所说的MongoDB是模式自由的。

查询多个文档

为了能够返回多个文档,我们可以使用find( )方法,返回一个游标实例,它允许我们遍历所有匹配的文档。

又一个栗子,我们可以遍历集合中所有的文档:

1
2
3
4
5
6
>>> for post in posts.find():
... post
...
{u'date': datetime.datetime(...), u'text': u'My first blog post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'mongodb', u'python', u'pymongo']}
{u'date': datetime.datetime(2009, 11, 12, 11, 14), u'text': u'Another post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'bulk', u'insert']}
{u'date': datetime.datetime(2009, 11, 10, 10, 45), u'text': u'and pretty easy too!', u'_id': ObjectId('...'), u'author': u'Eliot', u'title': u'MongoDB is fun'}

它也可以支持限制查找,我们可以限制作者为”Mike”:

1
2
3
4
5
>>> for post in posts.find({"author": "Mike"}):
... post
...
{u'date': datetime.datetime(...), u'text': u'My first blog post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'mongodb', u'python', u'pymongo']}
{u'date': datetime.datetime(2009, 11, 12, 11, 14), u'text': u'Another post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'bulk', u'insert']}

计数

如果我们只想知道文档数,可以用count()来实现:

1
2
>>> posts.count()
3

你们懂得,这里也可以做限制查找

1
2
>>> posts.find({"author": "Mike"}).count()
2

范围查询

MongoDB支持许多不同类型的高级查询。

栗子~栗子~,可以执行一个查询,我们限制结果为一个特定日期,同时按照作者排序:

1
>>> d=datetime.datetime(2009,11,12,12)>>> forpostinposts.find({"date":{"$lt":d}}).sort("author"):... printpost...{u'date': datetime.datetime(2009, 11, 10, 10, 45), u'text': u'and pretty easy too!', u'_id': ObjectId('...'), u'author': u'Eliot', u'title': u'MongoDB is fun'}{u'date': datetime.datetime(2009, 11, 12, 11, 14), u'text': u'Another post!', u'_id': ObjectId('...'), u'author': u'Mike', u'tags': [u'bulk', u'insert']}

这里我们用特殊的操作符”$lt”来做范围查询,同时用sort()做作者排序。

索引

添加索引可以加快某些查询,也可以增加一些额外的查询和存储文档功能。

在这个例子中,我们将演示如何创建一个惟一的键索引来拒绝那些已经在索引中存在的键对应的值的文档。
首先,创建一个索引

1
>>> result=db.profiles.create_index([('user_id',pymongo.ASCENDING)],... unique=True)>>> list(db.profiles.index_information())[u'user_id_1', u'_id_']

注意,我们现在有两个索引,一个是数据库自动创建的“_id”,另一个是我们刚创建的“user_id”。
现在让我们设置一些用户配置文件

1
2
3
4
>>> user_profiles = [
... {'user_id': 211, 'name': 'Luke'},
... {'user_id': 212, 'name': 'Ziltoid'}]
>>> result = db.profiles.insert_many(user_profiles)

索引可以防止插入时user_id重复:

1
>>> 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):pymongo.errors.DuplicateKeyError:E11000 duplicate key error index: test_database.profiles.$user_id_1 dup key: { : 212 }

原创文章,转载请注明: 转载自零の杂货铺