pymongo tutorial

原版英文文档

教程

这个教程只在介绍如何使用MongoDBPyMongo

准备前提

在我们开始之前,首先确认你已经正确安装了PyMongo ,在python shell 中如果下面的命令没有报错,则证明安装正确

>>>import pymongo

这个教程假设你已经正确安装了MongoDB,而且已经有一个instance运行在默认的host和port,如果你已经正确安装了mongodb可以使用下面进行启动

$mongod

和MongoClient建立连接

使用pymongo的第一步是创建一个MongoClient 用于和运行的mongod实例进行连接

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

上面的代码将会连接默认的Host和port.我们也可以手动指定host 和端口,比如:

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

或者使用mongodb url 格式地址:

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

获取数据库(Database)

一个mongodb实例可以支持多个独立的databse. 当使用pymongo的时候,你可以使用类似属性风格的方式访问MongoClient实例的database:

>>>db  = client.test_database

或者使用字典风格也可以

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

获取一个集合(collection)

一个集合(collection)是一系列储存在mongodb上的文档(document)的组,有点类似关系型数据库的表table。获取集合的方法类似获取数据库

>>>collection = db.test_collection

或者使用字典:

>>>collection = db['test-collection']

需要注意的是mongodb中的databases或者documents都是属于延迟创建(lazily created)的,上面所有的commands其实都没有对数据库进行任何实质性的操作。上面代码中的databases或者documents直到第一个documents被添加insert时才被创建

文档(documents)

数据在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 a document)

可以使用insert_one()来添加一条documents:

>>>posts = db.posts
>>>post_id = posts.insertone(post).inserted_id
>>>post_id
ObjectId('...')

当添加documents时候,如果‘id’值没有指定,则系统会自动生成一个'id'值,这个'_id'值在整个collection中是唯一的。inssert_one()返回一个InsertOneResult结果实例。

在添加了第一个document时,posts这个集合才在服务器上真正的创建。我们可以列出database中的集合collection来确认:

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

使用find_one()来得到一条document

最常使用的查询就是find_one()。他返回一条匹配的文档(如果没有匹配会返回None)。他经常被用在只有一条文档匹配,或者指向得到第一个匹配文档的情况。下面我们用他来返回post集合的第一条文档:

>>>posts.finde_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()添加一些匹配的参数:

>>>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']}

如果我们尝试一个不同的author,比如‘Eliot’就得不到结果:

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

通过ObjectId查询

我们也可以通过ObjectId进行查询:

>>> 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']}

注意ObjectId并不是一个简单的string

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

当我们进行web开发的时候,经常会需要将url中得到的ObjectId转换成pymongo可以识别的ObjectId,然后将他传递给find_one:

from bson.objectid import OjbectId
# 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 string和我们从服务器得到的并不一样(比如u'Mike' 'Mike'),这里我们简单的解释一下:

mongodb保存使用BSON 格式来保存数据。BSON string 都是UTF-8编码,所以pymongo必须确保所有的sting必须都是合法的UTF-8数据。常规的string储存不变???(regular string are validated and stored unaltered), Unicode编码的string首先会已utf-8编码。我们例子里面显示为u'Mike'而不是'Mike'的原因就是,pymongo首先解码每个BSON为PYHON unicode string,而不是常规的str (妈的,不懂)

关于pythong unicode string的详细阅读

批量添加 Bulk inserts

可以使用insert_many() 一次性添加多个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
[ObjectId('...'), ObjectId('...')]

关于上面这个例子需要注意两点:

  • 上面例子中insert_many()反悔了两个ObjectId实例,分别对应两个document
  • new_posts[1] 和其他的post的数据结构“shape”是不同的 - 一个有tag属性,一个有title属性,这就是我们常提到mongodb的自由结构(schema-free)特性 区别于传统的关系型数据库

查询得到多个文档

我们可以使用find()来一次性返回多个文档。find()返回一个指针cursor实例,可以用来遍历所有匹配的documents。
例如我可以用它来遍历所有的posts集合的所有documents:

>>>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'}

就像find_one()一样,我们也可以给他传递参数

>>> 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()方法进行计数,而不是返回一个完整的查询

>>> posts.count()
3

或者对返回的查询进行计数

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

范围查询

mongodb支持多种不同类型的高级查询。比如我可以查询一个早于特定时间的posts,然后按照author排序返回

>>> d = datetime.datetime(2009, 11, 12, 12)
>>> for post in posts.find({"date": {"$lt": d}}).sort("author"):
...   print post
...
{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()来对结果进行排序

索引

如果想让上述查询更快,我们可以给“date” 和"author"属性增加 元素索引。
为了显示增加索引后的效率提升,我们使用explain()方法来得到查询动作的次数:

>>> posts.find({"date": {"$lt": d}}).sort("author").explain()["cursor"]
u'BasicCursor'
>>> posts.find({"date": {"$lt": d}}).sort("author").explain()["nscanned"]
3

可以看到在没有索引的情况下,使用 基本指针basicCursor 总共扫描了集合中的3个文档,现在我们添加索引

>>>from pymongo import ASCENDING, DESCENDING
>>>posts.create_index([("date", DESCENDING), ("author"), ASCENDING])
u'date_-1_author_1'
>>>posts.find({'date':{"$lt":d}}).sort("author").explain(['curosr'])
u'BtreeCursor date_-1_author_1
>>> posts.find({"date": {"$lt": d}}).sort("author").explain()["nscanned"]
2

可以看到这次的衩裙使用 Btree指针 BtreeCursor 只扫描了两个文档就得到了结果

你可能感兴趣的:(pymongo tutorial)