技术标签: mongo 分析 pymongo find sort 数据库
简单来说,pymongo就是python关于Mongo db的一个包,主要是通过对一些命令的包装,通过socket发送给mongo服务,获取到一些结果,对结果进行包装,然后以包装为游标对象返回给使用者,其中游标对象实现了 next方法,同时对__next__进行更新,是的用户可以通过python迭代器进行迭代,逐条返回查询结果
来看具体分析:》》》
首先,通常情况下,我们这样使用:
mc = pymongo.MongoClient("remote_uri")
这是先生成了一个mongo客户端,返回的是一个MongoClien对象:
class MongoClient(common.BaseObject):
HOST = "localhost"
PORT = 27017
def __init__(
self,
host=None,
port=None,
document_class=dict,
tz_aware=False,
connect=True,
**kwargs):
......
......
然后会使用 db=mc["database_name"] 获取相应的数据库对象, 返回的是DataBase的实例:
-- mongo_client.py
def __getattr__(self, name):
"""Get a database by name.
Raises :class:`~pymongo.errors.InvalidName` if an invalid
database name is used.
:Parameters:
- `name`: the name of the database to get
"""
if name.startswith('_'):
raise AttributeError(
"MongoClient has no attribute %r. To access the %s"
" database, use client[%r]." % (name, name, name))
return self.__getitem__(name)
def __getitem__(self, name):
"""Get a database by name.
Raises :class:`~pymongo.errors.InvalidName` if an invalid
database name is used.
:Parameters:
- `name`: the name of the database to get
"""
return database.Database(self, name) ##################################主要看这里#########################################
同理,获取对应的集合的时候也是通过db["collection_name"]得到,返回的对象是Collection的实例:这个操作和上个类似,可以试着去找一找
得到collection的实例之后就有我们很常见的一些方法了,如下:
def find(self, *args, **kwargs):
return Cursoe(self, *args, **kwargs)
def find_one(self, filter=None, *args, **kwargs):
def insert_one(self, document):
def save(self, to_save, manipulate=True, check_keys=True, **kwargs):
还有很多,就不粘贴了。。
经常使用的 find 方法的返回结果是一个Cursor对象, 上面的代码可以看出。
接着重点来了:
很多的常见的函数,如sort, count,distinct,explain,min,max...都是Cursor中的方法,具体的实现原理可以自己去看看,这里只是对sort函数和怎么通过这个游标取数据进行分析。
首先是看一下sort函数都做了哪些事情:
def sort(self, key_or_list, direction=None):
"""Sorts this cursor's results.
"""
self.__check_okay_to_chain()
keys = helpers._index_list(key_or_list, direction)
self.__ordering = helpers._index_document(keys)
return self
由代码不难看出,sort函数在经过一系列操作之后,仍然是返回自身,也就是返回的韩式Cursor实例,只不过前面进行了三步操作。
三步执行完之后,并没有获取到真正的结果,文档的真实的获取结果是下面这个方法:
def next(self):
"""Advance the cursor."""
if self.__empty:
raise StopIteration
_db = self.__collection.database
if len(self.__data) or self._refresh():
if self.__manipulate:
return _db._fix_outgoing(self.__data.popleft(),
self.__collection)
else:
return self.__data.popleft()
else:
raise StopIteration
__next__ = next
这个函数结尾对__next__进行了重新赋值,使得可以通过python的迭代器进行迭代获取值。
def __send_message(self, operation):
"""Send a query or getmore operation and handles the response.
"""
client = self.__collection.database.client
if operation:
kwargs = {
"read_preference": self.__read_preference,
"exhaust": self.__exhaust,
}
if self.__address is not None:
kwargs["address"] = self.__address
try:
response = client._send_message_with_response(operation,
**kwargs)
self.__address = response.address
if self.__exhaust:
# 'response' is an ExhaustResponse.
self.__exhaust_mgr = _SocketManager(response.socket_info,
response.pool)
data = response.data
except AutoReconnect:
self.__killed = True
raise
else:
# Exhaust cursor - no getMore message.
try:
data = self.__exhaust_mgr.sock.receive_message(1, None)
except ConnectionFailure:
self.__die()
raise
try:
doc = helpers._unpack_response(response=data,
cursor_id=self.__id,
codec_options=self.__codec_options)
except OperationFailure:
.......
except NotMasterError:
.......
self.__id = doc["cursor_id"]
if self.__id == 0:
self.__killed = True
self.__retrieved += doc["number_returned"]
self.__data = deque(doc["data"]) ##########################################这里######################################
......
搜索这个__send_messae发现__refresh使用了这个方法,同时在next方法中发现了__refresh的踪迹,可见获取数据主要是通过不同的渠道进行__send_message获取得到的。
查看__send_message方法发现,是通过MongClient的实例调用_send_message_with_response方法获取,这个客户端又是通过回调的方式,调用了Server实例的send_message_with_response方法,返回的是Response对象(就是通过读取套接字中的内容,然后进行封装的),其代码如下:
class Response(object):
__slots__ = ('_data', '_address')
def __init__(self, data, address):
"""Represent a response from the server.
:Parameters:
- `data`: Raw BSON bytes.
- `address`: (host, port) of the source server.
"""
self._data = data
self._address = address
@property
def data(self):
"""Server response's raw BSON bytes."""
return self._data
@property
def address(self):
"""(host, port) of the source server."""
return self._address
主要是data属性,文档数据就存放在这个地方,到这,真正的数据也就找到了!
总结来说, 就是通过实例化相应的类,然后主要是通过Colllection对象的方法获取Cursor对象,对文档进行多种操作。本文主要是对find方法获取数据的过程进行分析,然后,简单说了一下常用的sort方法包含哪些过程,以加深对pymongo的理解。其中涉及到的类主要有:MongoClient, Collection, Cursor, Deque, Server, SocketInfo(获取信息), Response 。最后,有兴趣的可以看一下Collection下的aggregate方法,与find有一些不同,但大体实现原理类似!嗯,没了~~现在每次做一道bzoj上的题,整个人都感觉升华了。。。 先是在网上各种搜题解。要么只有代码,要么有点讲解看不懂,对于从来没有耐心看完别人代码的我,只能一篇一篇的翻。。然后终于在某2011级同学的某段话中找到了灵感,把它给A了。 我还是好好记录一下这道题的做题过程,不要又被其他人喷“只有做过的人才看得懂了!” 首先说说这道题的思路吧:dp+矩阵优化。dp虽然不那么明显...
有小伙伴问我,为什么不推荐他使用 Task.Factory.StartNew ,因为 Task.Run 是比较新的方法。本文告诉大家 Task.Run 和 Task.Factory.StartNew 区别
2019独角兽企业重金招聘Python工程师标准>>> ...
最近在学习uboot的移植,也看过很多文章,但多多少少都有些不尽人意的地方,自己手动移植也出现过种种问题。尤其是不能对移植的过程有很好的理解,基于这个原因,我打算深入学习一下uboot的移植过程,并对移植过程详细记录,方便那些想学习uboot移植确找不到门路的新手。 鉴于本人也是新手,文章难免有疏漏之处,也有自己不是很明白的地方,已经标记出来,还望各位多多指教。如果觉得好想转载,
1、百度搜索 GitHub 官网:https://github.com/2、搜索 axios3、点击 axios/axios4、下载到本地5、解压,进入到 dist 文件夹自己下载,不求人。
I am developing a cross platform app using Xamarin forms.I have an ObserveableCollection and I want to populate it with bluetooth devices that have been found during a search.The search is/has to be p...
1. 范数分析 (norm, normest) 常用于误差估计对于线性空间中某个向量 x = { x1, x2, ..., xn}, 其对应的p级范数定义为 abs(x)_p =(sum(abs(xi)^p),i=1,n)^(1/p), 而 +Inf 范数值 abs(x)_+Inf =max(abs(xi)), -Inf 为 abs(x)_-Inf = min(abs(xi));对于矩阵abs(A...
目录1、上传文件微服务2、zuul微服务(最简单的配置)3、利用zuul上传文件4、如果上传过大文件出现问题如下——超时1官方文档解决办法——可以传比较大的zip压缩图片啥的。。。。5、如果上传过大文件出现问题如下——the request was rejected because its size (26246240) exceeds the configured...
第一种分页 PageNumberPagination基本使用(1)urls.pyurlpatterns = [ re_path('(?P<version>[v1|v2]+)/page1/', Pager1View.as_view(),) #分页1](2)api/utils/serializers/pager.py# api/utils/serializse...
这次讲讲openwrt的结构.1. 代码上来看有几个重要目录package, target, build_root, bin, dl....---build_dir/host目录是建立工具链时的临时目录---build_dir/toolchain-<arch>*是对应硬件的工具链的目录---staging_dir/toolchain-<arch>* 则是工具链的安装位置---target/linux/<platform>目录里面是各个平台(arc.
下载并安装(下载地址:https://www.oracle.com/java/technologies/javase-jdk14-downloads.html)配置环境变量(管理员/系统)总之,方式都是一样的。我安装的路径是:D:\Program Files (x86)\Java\jdk-14.0.2配置系统变量,则在这部分配置JAVA_HOME和Path在用户变量中新建JAVA_HOME :D:\Program Files (x86)\Java\jdk-14.0.2CLASSPATH :.;%
刚好遇到要写微信小程序人脸识别的功能,就翻了一下微信小程序文档人脸识别跳转文档缺点:照片也可以成功。我试了一下眨眼,但是好像不行,闭眼都能识别到眼睛。然后没有demo,就自己研究了,记录一下。用uniapp写的,所以需要条件编译。HTML(需要用到相机组件)<view class=""> <camera v-if="showcamera" device-position="front" resolution="high" style="width: 100%; .