mongodb学习笔记
MongoDB
一、初识MongoDB
1.1 NoSQL
1.1.1 什么是NoSQL
NoSQL,全称是”Not Only Sql”,指的是非关系型的数据库。这类数据库主要有这些特点:
-
非关系型的
-
分布式的
-
开源的
-
水平可扩展的(数据之间没有关系)
-
高性能、高可用、高可拓展(三高问题)
nosql的缓存是一种细粒型的缓存 -----狂神说
原始的目的是为了大规模 web 应用。这场全新的数据库革命运动早期就有人提出,发展至 2009 年趋势越发高涨。NoSQL 的拥护者们提倡运用非关系型的数据存储,通常的应用如:模式自由、支持简易复制、简单的 API、最终的一致性(非 ACID)、大容量数据等。
传统数据库很难对付web2.0时代。
CAP定理和BASE理论
3V+3高问题
3V:
1. 海量 Volume 2. 多样 Variety 3. 实时 Velocity3高:高并发 高性能 高可拓
主要的NoSQL数据库类型:
-
key-value 存储
-
文档型
-
列存储
-
图型数据库
-
xml数据库
NoSQL 数据存储不需要固定的表结构,通常也不存在连接操作。在大数据存取上具备关系型数据库无法比拟的性能优势,该概念在 2009 年初得到了广泛认同。
| 类型 | 部分代表 | 特点 |
|---|---|---|
| 列存储 | Hbase、Cassandra、Hypertable | 顾名思义,是按列存储数据的。最大的特点是方便存储结构化和半结构化数据,方便做数据压缩,对针对某一列或者某几列的查询有非常大的IO优势。适合做大数据 |
| 文档存储 | MongoDB、CouchDB | 文档存储一般用类似json的格式存储,存储的内容是文档型的。这样也就有机会对某些字段建立索引,实现关系数据库的某些功能。适合web |
| key-value存储 | Tokyo Cabinet / TyrantBerkeley DB MemcacheDB、Redis | 可以通过key快速查询到其value。一般来说,存储不管value的格式,照单全收。(Redis包含了其他功能)。适合缓存 |
| 图存储 | Neo4J FlockDB | 图形关系的最佳存储。使用传统关系数据库来解决的话性能低下,而且设计使用不方便。 |
| 对象存储 | db4o Versant | 通过类似面向对象语言的语法操作数据库,通过对象的方式存取数据。 |
| xml数据库 | Berkeley DB XML BaseX | 高效的存储XML数据,并支持XML的内部查询语法,比如XQuery,Xpath。 |
1.1.2 数据库的发展
- 单机时代 90年代
- Memcached(缓存)+MySql+垂直拆分(读写分离
- 分库分表+水平拆分+集群
每个集群各存一部分数据
主-从模式
- 非关系型数据库
新时代,数据量多,变化快(比如地理位置信息,是个拓扑图)
诸如微博浏览量,每有个用户看一次就要持久化一次吗?(缓存)最近微博崩盘的例子
大的文件,比如万字博客、图片,不适合存在mysql里(图片数据库)
假如表里又1亿条数据,这个时候向关系型数据库加1列,怎么样?(列存储)
灰度发布:发行新版本的时候要平滑
目前互联网架构略图:
1.1.3 阿里巴巴演进分析
文档:阿里巴巴中文站架构实践
alibaba最早买的国外的PHP网站
1.2 MongoDB
它是一个面向集合的,模式自由的文档型数据库.
MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写
https://www.mongodb.com/官网
1、 面向集合(Collenction-Orented)
意思是数据被分组存储在数据集中, 被称为一个集合(Collenction)。每个集合在数据库中
都有一个唯一的标识名,并且可以包含无限数目的文档。集合的概念类似关系型数据库
(RDBMS)里的表(table),不同的是它不需要定义任何模式(schema)。
schema-free 模式自由
2、 模式自由(schema-free)
意味着对于存储在 MongoDB 数据库中的文件,我们不需要知道它的任何结构定义。提了这
么多次"无模式"或"模式自由",它到是个什么概念呢?例如,下面两个记录可以存在于同一
个集合里面:
{“welcome” : “Beijing”}
{“age” : 25}
3、 文档型
意思是我们存储的数据是键-值对的集合,键是字符串,值可以是数据类型集合里的任意类型,
包括数组和文档. 我们把这个数据格式称作 “BSON” 即 “Binary Serialized dOcument
Notation.”
1.2.1 BSON
BSON(/ˈbiːsən/)是一种计算机数据交换格式,主要被用作MongoDB数据库中的数据存储和网络传输格式。它是一种二进制表示形式,能用来表示简单数据结构、关联数组(MongoDB中称为“对象”或“文档”)以及MongoDB中的各种数据类型。BSON之名缘于JSON,含义为Binary JSON(二进制JSON)。
1.2.2 安装
windows下安装
行业规定:偶数版为稳定版,奇数版为开发版。
安装Compass会特别慢,建议先取消勾选,回头自己安装
./mongod --dbpath E:\MongoDB\Server\4.4\data\db
linux(CentOS7)下安装
官方文档:https://docs.mongodb.com/manual/tutorial/install-mongodb-on-red-hat/
-
配置yum源
vi /etc/yum.repos.d/mongodb-org-4.4.repo[mongodb-org-4.4] name=MongoDB Repository baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.4/x86_64/ gpgcheck=1 enabled=1 gpgkey=https://www.mongodb.org/static/pgp/server-4.4.asc -
安装
sudo yum install -y mongodb-org -
课外知识:init system
centos7 的init system是systemd(system daemon )(命令是systemctl开头的,老版的是service)
守护进程后面都喜欢加d
Linux 内核启动后,
init 进程是在 Fedora 上启动的第一个进程。进程 ID (PID) 为 1。它是系统中所有其它进程的母亲,用于启动其他服务和守护程序。可以用
ps --no-headers -o comm 1 #查看自己的系统用的是那一版的init system。了解即可,我在这里直接告诉大家:centos7抛弃了SystemV,开始使用systemd。
init system简介:
-
运行
启动还是systemd管理守护进程的那一套,systemctl + 命令 + 后面带d(daemon)的守护进程
sudo systemctl start mongod sudo systemctl status mongod #看看启动没有 sudo systemctl stop mongod #关闭 sudo systemctl restart mongod #重启开始使用:
mongo #默认端口27017,默认http端口28017 -
修改配置文件
By default, MongoDB launches with
bindIpset to127.0.0.1, which binds to the localhost network interface. This means that themongodcan only accept connections from clients that are running on the same machine. Remote clients will not be able to connect to themongod, and themongodwill not be able to initialize a replica set unless this value is set to a valid network interface.默认MongoDB以bindIP设置为127.0.0.1(和本地网络接口绑定)启动。这意味着mongod只能接受在相同的机器上运行的客户端的连接。
远程客户端将不能连接上mongod,并且mongod不能初始化一个复制集,除非这个值被设置成一个有效的网络接口。
# vi /etc/mongod.confbindIp: 0.0.0.0 # Enter 0.0.0.0,:: to bind to all IPv4 and IPv6 addresses or, alternatively, use the net.bindIpAll setting.将bindIp改为0.0.0.0,允许所有的 ipv4和ipv6地址。或者用net.bindall设置。
1.2.3 数据逻辑结构
我在这里给大家简单的介绍一下 MongoDB 体系结构之-的逻辑结构。MongoDB 的逻辑结构是一种层次结构。主要由:
文档(document)、集合(collection)、数据库(database)这三部分组成的。逻辑结构是面向用户的,用户使用 MongoDB 开发应用程序使用的就是逻辑结构。
- MongoDB 的文档(document),相当于关系数据库中的一行记录。
- 多个文档组成一个集合(collection),相当于关系数据库的表。
- 多个集合,逻辑上组织在一起,就是数据库(database)。
- 一个 MongoDB 实例支持多个数据库(database)。

下表列出了 RDBMS 与 MongoDB 对应的术语:
| RDBMS | MongoDB |
|---|---|
| 数据库 | 数据库 |
| 表格 | 集合 |
| 行 | 文档 |
| 列 | 字段 |
| 表联合 | 嵌入文档 |
| 主键 | 主键 (MongoDB 提供了 key 为 _id ) |
| 数据库服务和客户端 | |
| Mysqld/Oracle | mongod |
| mysql/sqlplus | mongo |
需要注意的是:
- 文档中的键/值对是有序的。
- 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。mongodb数据类型
- MongoDB区分类型和大小写。
- MongoDB的文档不能有重复的键。
- 文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。如果不加引号,也会自动转为字符串。
文档键命名规范:
- 键不能含有\0 (空字符)。这个字符用来表示键的结尾。
- .和$有特别的意义,只有在特定环境下才能使用。
- 以下划线"_"开头的键是保留的(不是严格要求的)。
二、开始使用MongoDB吧!
2.1 文档操作-CRUD
打开bin目录下的mongo.exe,进入mongo shell。
MongoDB Shell是MongoDB自带的交互式Javascript shell,用来对MongoDB进行操作和管理的交互式环境。
2.1.1 插入文档
注:以下例子中,默认使用的集合名字为collection
db.collection.insertOne({name:'zhangsan'})
db.collention.insertMany([
{"_id":1,name:'lisi'},
{"name":zhangsan,skills:{java:'spring',python:'flask'}}
])
第一次向某一集合写入文档的时候会自动创建集合。
如果插入的文档没有指定"_id"字段,将会自动生成ObjectID
注意:ObjectId类型的_id和String类型的是不同的!!可以在mongoshell里试一下,用js的toString方法
返回值:insertMany()返回一个装有成功插入的_id的文档
2.1.2 删除文档
3.2版本后:目前官网推荐使用:
db.collection.deleteOne()New in version 3.2db.collection.deleteMany()New in version 3.2
老版本方法:如果你的 MongoDB 是 2.6 版本以后的,语法格式如下:
db.collection.remove( <query>, { justOne: <boolean>, writeConcern: <document> )参数说明:
- query :(可选)删除的文档的条件。
- justOne : (可选)如果设为 true 或 1,则只删除一个文档。
- writeConcern :(可选)抛出异常的级别。
db.collections.remove({}) /*删除所有*/
2.1.3 更新
>db.collecions.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}},{multi:true})
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
}
)
参数说明:
- query : update的查询条件,类似sql update查询内where后面的。
- update : update的对象和一些更新的操作符(如 , , ,inc…)等,也可以理解为sql update查询内set后面的
- upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
- multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
- writeConcern :可选,抛出异常的级别。
更新操作符:
| Name | Description |
|---|---|
$currentDate |
Sets the value of a field to current date, either as a Date or a Timestamp. |
$inc |
Increments the value of the field by the specified amount.自增,可指定步长 |
$min |
Only updates the field if the specified value is less than the existing field value. |
$max |
Only updates the field if the specified value is greater than the existing field value. |
$mul |
Multiplies the value of the field by the specified amount. |
$rename |
Renames a field. |
$set |
Sets the value of a field in a document. |
$setOnInsert |
Sets the value of a field if an update results in an insert of a document. Has no effect on update operations that modify existing documents. |
$unset |
Removes the specified field from a document. |
2.1.4 查询
1)普通查询
PS:inventory是官方文档在线练习中默认的集合名字,译为库存、存货、详细目录
# 查询所有
db.inventory.find( {} )
#条件查询
db.test.find({name:'zhangsan'})
#用查询运算符查询
##查询name是A或者D的
db.test.find({name:{$in:["A","D"]}})
##AND查询:用,分隔
db.test.find({name:{$in:["A","D"]}})
## or :
db.inventory.find( { $or: [ { status: "A" }, { qty: { $lt: 30 } } ] } )
## and + or +正则:
db.inventory.find( {
status: "A",
$or: [ { qty: { $lt: 30 } }, { item: /^p/ } ]
} )
find()方法返回一个cursor
在查询条件只有一个字段时,官方推荐使用 i n 而不是 in而不是 in而不是or,尽管能达到同样的效果
尽管
2)嵌套文档查询
必须精确匹配,包括文档中字段的顺序。
查询条件缺失部分字段能不能查询到呢?
不能。必须精确匹配。其他字段搜索不需要精确,只有文档型的字段要求精确匹配。
#插入数据
db.inventory.insertMany( [
{ item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
{ item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "A" },
{ item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },
{ item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },
{ item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" }
]);
#可以查到数据
db.inventory.find( { size: { h: 14, w: 21, uom: "cm" } } )
#查不到数据,因为顺序不一样
db.inventory.find( { size: { w: 21, h: 14, uom: "cm" } } )
#查询条件中缺少部分字段,依然查询不到
db.inventory.find( { size: { uom: "cm" } } )
#用点表示法("field.nestedField")
db.inventory.find( { "size.uom": "in" } )
用操作符查询
查询过滤器文档(query filter document)可以使用查询操作符,格式如下
{ : { : }, … }
#相当于把原来放集体条件的值的地方换成一个文档过滤器
db.inventory.find( { "size.h": { $lt: 15 } } )
3)数组查询
同样,指定条件的数组查询要求精确匹配,包括数组中的顺序
#插入数据
db.inventory.insertMany([
{ item: "journal", qty: 25, tags: ["blank", "red"], dim_cm: [ 14, 21 ] },
{ item: "notebook", qty: 50, tags: ["red", "blank"], dim_cm: [ 14, 21 ] },
{ item: "paper", qty: 100, tags: ["red", "blank", "plain"], dim_cm: [ 14, 21 ] },
{ item: "planner", qty: 75, tags: ["blank", "red"], dim_cm: [ 22.85, 30 ] },
{ item: "postcard", qty: 45, tags: ["blue"], dim_cm: [ 10, 15.25 ] }
]);
#匹配第二条
db.inventory.find( { tags: ["red", "blank"] } )
#如果想要查询出所有包含red和blank的文档,不论顺序或数组中有没有其他元素
db.inventory.find( { tags: { $all: ["red", "blank"] } } )
$all运算符只能在数组中用。
#指定条件查询
db.inventory.find( { tags: "red" } )
#{ <array field>: { <operator1>: <value1>, ... } }
#数组中有一个元素满足就会被筛选出来
db.inventory.find( { dim_cm: { $gt: 25 } } )
#数组里有一个满足大于15另一个满足小于20,或者一个数满足两个条件均可
#比喻:(团队合作)
db.inventory.find( { dim_cm: { $gt: 15, $lt: 20 } } )
# $elemMatch:至少一个元素同时满足所有条件
#比喻:(个人秀)
db.inventory.find( { dim_cm: { $elemMatch: { $gt: 22, $lt: 30 } } } )
4) t y p e 和 type和 type和exists 数据类型
$type操作符是基于BSON类型来检索集合中匹配的数据类型,并返回结果。
| Type | Number | Alias | Notes |
|---|---|---|---|
| Double | 1 | “double” | |
| String | 2 | “string” | |
| Object | 3 | “object” | |
| Array | 4 | “array” | |
| Binary data | 5 | “binData” | |
| Undefined | 6 | “undefined” | Deprecated. |
| ObjectId | 7 | “objectId” | |
| Boolean | 8 | “bool” | |
| Date | 9 | “date” | |
| Null | 10 | “null” | |
| Regular Expression | 11 | “regex” | |
| DBPointer | 12 | “dbPointer” | Deprecated. |
| JavaScript | 13 | “javascript” | |
| Symbol | 14 | “symbol” | Deprecated. |
| JavaScript code with scope | 15 | “javascriptWithScope” | Deprecated in MongoDB 4.4. |
| 32-bit integer | 16 | “int” | |
| Timestamp | 17 | “timestamp” | |
| 64-bit integer | 18 | “long” | |
| Decimal128 | 19 | “decimal” | New in version 3.4. |
| Min key | -1 | “minKey” | |
| Max key | 127 | “maxKey” |
$exits过滤是否包含某个字段的文档.
以下例子查询不包括"item"字段的文档.
cursor = db.inventory.find({"item": {"$exists": False}})
5) 聚合 && 管道
{
_id: ObjectId(7df78ad8902c)
title: 'MongoDB Overview',
description: 'MongoDB is no sql database',
by_user: 'runoob.com',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
},
{
_id: ObjectId(7df78ad8902d)
title: 'NoSQL Overview',
description: 'No sql database is very fast',
by_user: 'runoob.com',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 10
},
{
_id: ObjectId(7df78ad8902e)
title: 'Neo4j Overview',
description: 'Neo4j is no sql database',
by_user: 'Neo4j',
url: 'http://www.neo4j.com',
tags: ['neo4j', 'database', 'NoSQL'],
likes: 750
},
现在我们通过以上集合计算每个作者所写的文章数,使用aggregate()计算结果如下:
> db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}])
{
"result" : [
{
"_id" : "runoob.com",
"num_tutorial" : 2
},
{
"_id" : "Neo4j",
"num_tutorial" : 1
}
],
"ok" : 1
}
>
以上实例类似sql语句:
select by_user, count(*) from mycol group by by_user
在上面的例子中,我们通过字段 by_user 字段对数据进行分组(对by_user相同的计算count),并计算 by_user 字段相同值的总和。
下表展示了一些聚合的表达式:
| 表达式 | 描述 | 实例 |
|---|---|---|
| $sum | 计算总和。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { s u m : " sum : " sum:"likes"}}}]) |
| $avg | 计算平均值 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { a v g : " avg : " avg:"likes"}}}]) |
| $min | 获取集合中所有文档对应值得最小值。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { m i n : " min : " min:"likes"}}}]) |
| $max | 获取集合中所有文档对应值得最大值。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { m a x : " max : " max:"likes"}}}]) |
| $push | 在结果文档中插入值到一个数组中。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", url : { p u s h : " push: " push:"url"}}}]) |
| $addToSet | 在结果文档中插入值到一个数组中,但不创建副本。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", url : { a d d T o S e t : " addToSet : " addToSet:"url"}}}]) |
| $first | 根据资源文档的排序获取第一个文档数据。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", first_url : { f i r s t : " first : " first:"url"}}}]) |
| $last | 根据资源文档的排序获取最后一个文档数据 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", last_url : { l a s t : " last : " last:"url"}}}]) |
2.2 数据库操作
2.2.1 创建数据库 && 查看数据库和集合
use DATABASE_NAME
若数据库不存在,则直接创建。
默认是test数据库
show dbs /*查看所有数据库,看不到刚刚创建还没有插入文档的*/
db /*查看当前数据库*/
show collections /*查看当前数据库有哪些集合*/
2.2.2 删除数据库
db.dropDatabase()
删除当前数据库
2.2.3 删除集合
db.集合名.drop()
创建集合
默认在第一次像集合中插入数据时,会创建集合。
可以显示的创建集合
db.createCollection("people")
可以自己创建固定大小的集合:capped collections 注:capped译为“有上限的”
和普通的collection不同,capped collection必须显式的创建,并指定一个的大小,单位是字节。
db.createCollection("mycoll", {capped:true, size:100000})
- 在 capped collection 中,你能添加新的对象。
- 能进行更新,然而,对象不会增加存储空间。如果增加,更新就会失败 。
- 使用 Capped Collection 不能删除一个文档,可以使用 drop() 方法删除 collection 所有的行。
- 删除之后,你必须显式的重新创建这个 collection。
- 由于 Capped collection 是按照文档的插入顺序而不是使用索引确定插入位置,这样的话可以提高增添数据的效率。
三、python操作MongoDB
安装PyCharm插件

在Plugins->Marketplace中搜索mongo,找到Mongo Plugin(我已经安装过了所以我的在Installed中)

安装后重启,可在右边见到MongoDB Explorer
PyMongo
PyMongo是官网推荐的使用Python操作MongoDB的方式。Motor是推荐使用的MongoDB Python异步驱动。
可以在mongoDB官方文档中找到使用教程
推荐使用pip安装PyMongo:
pip install pymongo
MongoDB是C/S架构,需要客户端(Client)去连接位于主机的服务端。平时我们用的mongo shell就是客户端,现在使用Python来创建客户端对象MongoClient。

##获取MongoClient对象
from pymongo import MongoClient
#三种创建client的方式
client = MongoClient() #无参数,连接默认的主机和端口
client = MongoClient('localhost',27017) #双参数:主机和端口
client = MongoClient('mongodb://localhost:27017/') #使用MongoDB URI的方式,写法和jdbc类似
获取db对象
有了client,下一步自然就是获取db–数据库对象了。可以通过两种写法获取db对象:
- 通过获取属性风格的写法 但是这种方式,数据库名要符合变量的命名规范。如果你的数据库名为
test-database,因为有’-',那么将无法通过此方法获取数据库对象 - 通过字典风格的写法
db = client.test_database #属性风格
db = client['test-database'] #字典风格
获取集合对象
和获取数据库对象相同,可以使用两种风格
collection = db.test_collection
collection = db['test-collection']
文档操作
在python中,我们可以用字典来代表JSON对象。毕竟都是键值对的格式嘛。
注意文档python自有的对象类型(像datetime.datetime的实例)将会被自动转化成合适的BSON对象。
插入一个文档
可以通过集合类对象的insert_one(document)方法来插入一条文档。
from pymongo import MongoClient
client = MongoClient()
db = client.py #使用名为py数据库
collection = db.collection
insert_one_result = collection.insert_one({'name': '马保国', 'age': 63})
可以发现,pymongo中关于文档操作的函数名,都只是将mongoDB中对应的函数名转换为PEP8标准格式的函数名,即’函数名应该小写,如果想提高可读性可以用下划线分隔’。比如本例中的insertOne()=>insert_one()
在之前使用mongo shell时我们就知道,mongodb不用显示地创建集合,等到向集合中插入第一条数据时,mongodb会自动创建集合。但在上面的例子中,可以在插入数据前就获得colletion对象。事实上,这个时候在mongodb的服务端并没有创建collection集合,只有在插入第一条数据时,==服务端(server)==才会创建该集合。
insert_one()方法的一些说明
- Collection类的insert_one()方法返回一个
pymongo.results.InsertOneResult类的对象。可以访问该对象的inserted_id属性来获得插入文档的__id_。若插入相同_id,则会抛出异常。- 参数document为必需参数,且不能为None。
为什么Python可以做到像访问属性一样访问任意名称的数据库、集合?类中的属性不应该是已经定义死的嘛?
- pymongo重写了类的
__getattr__和__getitem__两个专有方法,类似于类的运算符重载。重写后,当用属性或是索引(即object[索引])的方式访问DataBase类和MongoClient类的属性时,DataBase类或MongoClient类的对象会返回一个相应的实例,而不是真正的访问类中的属性。- MongoClient类中相应的源码如下:
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)
查询一个:find_one()
如果不传参数,则为查询第一条;可以传入字典类型的参数,查询符合条件的第一条或是返回None
在web项目中,我们从请求中获得的_id为str类型,如果查询ObjectId类型的_id是查不出来的,因此要先强制转换成ObjectId类型再查询
批量插入
像insert_many()的第一个参数插入一个列表,只向服务端发送一条命令就可以插入列表中的每个文档。
批量查询
find()方法返回一个Cursor对象,可以迭代遍历其中的每个文档。find()方法将会返回每个匹配的文档。
for user in collection.find():
print(user)
#加入查询条件
for user in collection.find({'name': '马保国'}):
print(user)
#查询后按条件排序
for user in collection.find().sort("name"):
print(user)
find()进阶 && 分页查询:limit()和skip()
db.col.find({},{"title":1,_id:0}).limit(2).skip(20)
补充说明:
-
第一个 {} 放 where 条件,为空表示返回集合中所有文档。
-
第二个 {} 指定那些列显示和不显示 (0表示不显示 1表示显示)。
-
limit和skip相当于sql中的limit(22,2)
-
skip是一条一条跳过的,效率较慢
-
skip(), limilt(), sort()三个放在一起执行的时候,执行的顺序是先 sort(), 然后是 skip(),最后是显示的 limit()。
-
#效率更高的分页 b.test.sort({"amount":1}).skip(100000).limit(10) #183ms db.test.find({amount:{$gt:2399927}}).sort({"amount":1}).limit(10) #53ms,1表示升序排序
索引
添加索引可以帮助我们加快准确查询的速度并未查询和存储文档增加功能性。在这个例子中,我们将会展示如忽然在一个键上建立唯一索引,以拒绝在这个键上的值已经在索引中存在的文档。
首先,我们创建索引
>>> result = db.collection.create_index([('user_id', pymongo.ASCENDING)],unique=True)
...
>>> sorted(list(db.collection.index_information()))
[u'_id_', u'user_id_1']
注意我们现在有了两个索引:一个是在_id上的索引,是MongoDB自动创建的,而另一个是我们刚在user_id上创建的。此时,向该集合中新插入的文档不允许出现重复的user_id的值。
四、复制(副本集)
- 保障数据的安全性
- 数据高可用性 (24*7)
- 灾难恢复
- 无需停机维护(如备份,重建索引,压缩)
- 分布式读取数据
五、关系
- 1对1 1:1
- 1对多 1:n
- 多对多 n:n
和关系型数据库不同,mongdb中一对多关系可以在"1"的一方添加多的一方的主键。
Spring Data Mongodb
和Spring Data Elasticsearch类似,Spring Data Mongodb是Spring提供的一种以Spring Data风格来操作数据存储的方式,它可以避免编写大量的样板代码。
- @Document:标示映射到Mongodb文档上的领域对象
- @Id:标示某个域为ID域
- @Indexed:标示某个字段为Mongodb的索引字段
Sping Data方式的数据操作
继承MongoRepository接口可以获得常用的数据操作方法
在pom.xml中添加相关依赖
<!---mongodb相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
修改SpringBoot配置文件
修改application.yml文件,在spring:data节点下添加Mongodb相关配置。
mongodb:
host: localhost # mongodb的连接地址
port: 27017 # mongodb的连接端口号
database: mall-port # mongodb的连接的数据库
附录
- 不是 Blob 存储——如果必须不断地反序列化 Blob 并附加到它们,那么每秒写入数千条消息的效果并不好。
最近在 Discord 的技术 blog 看到 Discord 的底层数据存储的演进过程,从最开始的 2015 初用的单个副本集的 MongoDB,2015 年底迁移到 Cassandra,2022 年消息量达到了万亿的级别,他们将存储迁移到 ScyllaDB。
Mongodb
和Spring Data Elasticsearch类似,Spring Data Mongodb是Spring提供的一种以Spring Data风格来操作数据存储的方式,它可以避免编写大量的样板代码。
- @Document:标示映射到Mongodb文档上的领域对象
- @Id:标示某个域为ID域
- @Indexed:标示某个字段为Mongodb的索引字段
Sping Data方式的数据操作
继承MongoRepository接口可以获得常用的数据操作方法
在pom.xml中添加相关依赖
<!---mongodb相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
修改SpringBoot配置文件
修改application.yml文件,在spring:data节点下添加Mongodb相关配置。
mongodb:
host: localhost # mongodb的连接地址
port: 27017 # mongodb的连接端口号
database: mall-port # mongodb的连接的数据库

附录
- 不是 Blob 存储——如果必须不断地反序列化 Blob 并附加到它们,那么每秒写入数千条消息的效果并不好。
最近在 Discord 的技术 blog 看到 Discord 的底层数据存储的演进过程,从最开始的 2015 初用的单个副本集的 MongoDB,2015 年底迁移到 Cassandra,2022 年消息量达到了万亿的级别,他们将存储迁移到 ScyllaDB。
Discord 在创建之初采用的是一个单副本集的 MongoDB,没有使用 MongoDB 的分片,他们给出的理由是当时 MongoDB 分片很难用,而且不够稳定(这里就不去深究了)。消息数到达一亿条时,RAM 里已经存不下这么数据和索引,MongoDB 的延时开始变得不可控。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)