赞
踩
思维导图:
课程目标
MongoDB的副本集: 操作, 主要概念, 故障转移, 选举规则 MongoDB的分片集群:概念, 优点, 操作, 分片策略, 故障转移 MongoDB的安全认证
传统的关系型数据库 (比如 MySQL), 在数据操作的”三高”需求以及对应的 Web 2.0 网站需求面前, 会有”力不从心”的感觉
所谓的三高需求:
高并发, 高性能, 高可用, 简称三高
而 MongoDB 可以应对三高需求
具体的应用场景:
这些应用场景中, 数据操作方面的共同点有:
对于这样的数据, 更适合用 MongoDB 来实现数据存储
那么我们什么时候选择 MongoDB 呢?
除了架构选型上, 除了上述三个特点之外, 还要考虑下面这些问题:
99.999%
高可用如果上述有1个符合, 可以考虑 MongoDB, 2个及以上的符合, 选择 MongoDB 绝不会后悔.
如果上述业务场景使用用MySQL呢?
显然相对于MySQL, MongoDB可以以更低的成本解决问题(包括学习, 开发, 运维等成本)
MongoDB是一个开源, 高性能, 无模式的文档型数据库, 当初的设计就是用于简化开发和方便扩展, 是NoSQL数据库产品中的一种.是最 像关系型数据库(MySQL)的非关系型数据库. 它支持的数据结构非常松散, 是一种类似于 JSON 的 格式叫BSON, 所以它既可以存储比较复杂的数据类型, 又相当的灵活. MongoDB中的记录是一个文档, 它是一个由字段和值对(field:value)组成的数据结构.MongoDB文档类似于JSON对象, 即一个文档认 为就是一个对象.字段的数据类型是字符型, 它的值除了使用基本的一些类型外, 还可以包括其他文档, 普通数组和文档数组.
“最像关系型数据库的 NoSQL 数据库”. MongoDB 中的记录是一个文档, 是一个 key-value pair. 字段的数据类型是字符型, 值除了使用基本的一些类型以外, 还包括其它文档, 普通数组以及文档数组
Mongo和Mysql对比
MongoDB 数据模型是面向文档的, 所谓文档就是一种类似于 JSON 的结构, 简单理解 MongoDB 这个数据库中存在的是各种各样的 JSON(BSON)
在 MongoDB 中, 数据库和集合都不需要手动创建, 当我们创建文档时, 如果文档所在的集合或者数据库不存在, 则会自动创建数据库或者集合
操作 | 语法 |
---|---|
查看所有数据库 | show dbs; 或 show databases; |
查看当前数据库 | db; |
切换到某数据库 (若数据库不存在则创建数据库) | use <db_name>; |
删除当前数据库 | db.dropDatabase(); |
操作 | 语法 |
---|---|
查看所有集合 | show collections; |
创建集合 | db.createCollection("<collection_name>"); |
删除集合 | db.<collection_name>.drop() |
MongoDB的最小存储单位就是文档(document)对象。文档(document)对象对应于关系型数据库的行。数据在MongoDB中以 BSON(Binary-JSON)文档的格式存储在磁盘上。
BSON(Binary Serialized Document Format)是一种类json的一种二进制形式的存储格式,简称Binary JSON。BSON和JSON一样,支持 内嵌的文档对象和数组对象,但是BSON有JSON没有的一些数据类型,如Date
和BinData
类型。
BSON采用了类似于 C 语言结构体的名称、对表示方法,支持内嵌的文档对象和数组对象,具有轻量性、可遍历性、高效性的三个特点,可以有效描述非结构化数据和结构化数据。这种格式的优点是灵活性高,但它的缺点是空间利用率不是很理想。
Bson中,除了基本的JSON类型:string,integer,boolean,double,null,array和object,mongo还使用了特殊的数据类型。这些类型包括 date,object id,binary data,regular expression 和code。每一个驱动都以特定语言的方式实现了这些类型,查看你的驱动的文档来获取详细信息。
提示: shell默认使用64位浮点型数值。{“x”:3.14}或{“x”:3}。对于整型值,可以使用NumberInt(4字节符号整数)或NumberLong(8字节符 号整数),{“x”:NumberInt(“3”)}{“x”:NumberLong(“3”)}
MongoDB 提供高性能的数据持久化
MongoDB 的复制工具称作副本集 (replica set) 可以提供自动故障转移和数据冗余
水平扩展是其核心功能一部分
分片将数据分布在一组集群的机器上 (海量数据存储, 服务能力水平扩展)
MongoDB 支持基于片键创建数据区域, 在一个平衡的集群当中, MongoDB 将一个区域所覆盖的读写只定向到该区域的那些片
MongoDB支持丰富的查询语言, 支持读和写操作(CRUD), 比如数据聚合, 文本搜索和地理空间查询等.
无模式(动态模式), 灵活的文档模型
MongoDB安装请看本文的第八点
操作 | 语法 |
---|---|
查看所有数据库 | show dbs; 或 show databases; |
查看当前数据库 | db; |
切换到某数据库 (若数据库不存在则创建数据库) | use <db_name>; |
删除当前数据库 | db.dropDatabase(); |
默认保留的数据库
admin: 从权限角度考虑, 这是 root
数据库, 如果将一个用户添加到这个数据库, 这个用户自动继承所有数据库的权限, 一些特定的服务器端命令也只能从这个数据库运行, 比如列出所有的数据库或者关闭服务器
local: 数据永远不会被复制, 可以用来存储限于本地的单台服务器的集合 (部署集群, 分片等)
config: Mongo 用于分片设置时, config
数据库在内部使用, 用来保存分片的相关信息
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
> use articledb
switched to db articledb
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
当我们创建了一个数据库后再进行查看会发现,我们创建的数据库并没有显示出来,这是由于MongoDD的存储机制决定的
当使用
use articledb
的时候.articledb
其实存放在内存之中, 当articledb
中存在一个 collection 之后, mongo 才会将这个数据库持久化到硬盘之中.
> show dbs admin 0.000GB config 0.000GB local 0.000GB > use articledb switched to db articledb > show dbs admin 0.000GB config 0.000GB local 0.000GB > db.articledb.insertOne({"a": 3}) { "acknowledged" : true, "insertedId" : ObjectId("62e128b6a70e7344a5139207") } > show dbs admin 0.000GB articledb 0.000GB config 0.000GB local 0.000GB
另外: 数据库名可以是满足以下条件的任意UTF-8字符串。
' '
空格)、.
、$
、/
、\
和 \0
(空字符)。集合操作与数据库操作类似,这里不再单独演示
官方文档: https://docs.mongodb.com/manual/crud/
Create or insert operations add new documents to a collection. If the collection does not currently exist, insert operations will create the collection automatically.
文档的数据结构和 JSON 基本一样。
所有存储在集合中的数据都是 BSON 格式。
BSON 是一种类似 JSON 的二进制形式的存储格式,是 Binary JSON 的简称
使用 db.<collection_name>.insertOne()
向集合中添加一个文档, 参数一个 json 格式的文档
-db.collection.insertOne() 用于向集合插入一个新文档,语法格式如下:
db.collection.insertOne(
<document>,
{
writeConcern: <document>
}
)
使用 db.<collection_name>.insertMany()
向集合中添加多个文档, 参数为 json 文档数组
db.collection.insertMany() 用于向集合插入一个多个文档,语法格式如下:
db.collection.insertMany(
[ <document 1> , <document 2>, ... ],
{
writeConcern: <document>,
ordered: <boolean>
}
)
参数说明:
我们平时使用最多的只有
document
这一个字段
# 插入单条数据 > var document = db.collection.insertOne({"a": 3}) > document { "acknowledged" : true, "insertedId" : ObjectId("571a218011a82a1d94c02333") } # 插入多条数据 > var res = db.collection.insertMany([{"b": 3}, {'c': 4}]) > res { "acknowledged" : true, "insertedIds" : [ ObjectId("571a22a911a82a1d94c02337"), ObjectId("571a22a911a82a1d94c02338") ] }
还可以通过js函数方式批量插入文档:
1、先创建数组
2、将数据放在数组中
3、一次 insert 到集合中
var arr = [];
for(var i=1 ; i<=20000 ; i++){
arr.push({num:i});
}
db.numbers.insert(arr);
注:当我们向 collection
中插入 document
文档时, 如果没有给文档指定 _id
属性, 那么数据库会为文档自动添加 _id
field, 并且值类型是 ObjectId(blablabla)
, 就是文档的唯一标识, 类似于 relational database 里的 primary key
- mongo 中的数字, 默认情况下是 double 类型, 如果要存整型, 必须使用函数
NumberInt(整型数字)
, 否则取出来就有问题了- 插入当前日期可以使用
new Date()
如果某条数据插入失败, 将会终止插入, 但已经插入成功的数据不会回滚掉. 因为批量插入由于数据较多容易出现失败, 因此, 可以使用 try catch
进行异常捕捉处理, 测试的时候可以不处理.如:
try {
// 插入多条记录
db.comment.insertMany([
{"_id":"1","articleid":"100001","content":"我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-08-05T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"},
{"_id":"2","articleid":"100001","content":"我夏天空腹喝凉开水,冬天喝温开水","userid":"1005","nickname":"伊人憔悴","createdatetime":new Date("2019-08-05T23:58:51.485Z"),"likenum":NumberInt(888),"state":"1"},
{"_id":"3","articleid":"100001","content":"我一直喝凉开水,冬天夏天都喝。","userid":"1004","nickname":"杰克船长","createdatetime":new Date("2019-08-06T01:05:06.321Z"),"likenum":NumberInt(666),"state":"1"},
{"_id":"4","articleid":"100001","content":"专家说不能空腹吃饭,影响健康。","userid":"1003","nickname":"凯撒","createdatetime":new Date("2019-08-06T08:18:35.288Z"),"likenum":NumberInt(2000),"state":"1"},
{"_id":"5","articleid":"100001","content":"研究表明,刚烧开的水千万不能喝,因为烫嘴。","userid":"1003","nickname":"凯撒","createdatetime":new Date("2019-08-06T11:01:02.521Z"),"likenum":NumberInt(3000),"state":"1"}
]);
} catch (e) {
print (e);
}
更多查询可以看2.4节和2.5节
db.<collection_name>.find()
方法对集合进行查询, 接受一个 json 格式的查询条件. 返回的是一个数组db.<collection_name>.findOne()
查询集合中符合条件的第一个文档, 返回的是一个对象// 插入多条记录 > db.comment.insertMany([ {"_id":"1","articleid":"100001","content":"我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-08-05T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"}, {"_id":"2","articleid":"100001","content":"我夏天空腹喝凉开水,冬天喝温开水","userid":"1005","nickname":"伊人憔悴","createdatetime":new Date("2019-08-05T23:58:51.485Z"),"likenum":NumberInt(888),"state":"1"}, {"_id":"3","articleid":"100001","content":"我一直喝凉开水,冬天夏天都喝。","userid":"1004","nickname":"杰克船长","createdatetime":new Date("2019-08-06T01:05:06.321Z"),"likenum":NumberInt(666),"state":"1"}, {"_id":"4","articleid":"100001","content":"专家说不能空腹吃饭,影响健康。","userid":"1003","nickname":"凯撒","createdatetime":new Date("2019-08-06T08:18:35.288Z"),"likenum":NumberInt(2000),"state":"1"}, {"_id":"5","articleid":"100001","content":"研究表明,刚烧开的水千万不能喝,因为烫嘴。","userid":"1003","nickname":"凯撒","createdatetime":new Date("2019-08-06T11:01:02.521Z"),"likenum":NumberInt(3000),"state":"1"} ]); { "acknowledged" : true, "insertedIds" : [ "1", "2", "3", "4", "5" ] } // 只返回查询到的第一条数据 > db.comment.findOne({"articleid":"100001"}) { "_id" : "1", "articleid" : "100001", "content" : "我们不应该把清晨浪费在手机上,健康很重要,一杯温水幸福你我他。", "userid" : "1002", "nickname" : "相忘于江湖", "createdatetime" : ISODate("2019-08-05T22:08:15.522Z"), "likenum" : 1000, "state" : "1" } // 等价于 db.comment.find({"articleid":"100001"}).limit(1)
如果我们不需要那么多的字段,我们可以在查询条件后面再跟上需要查询的字段,1
表示显示指定的字段,其中_id
是默认显示的,我们指定0
表示强制不显示
// 只显示articleid字段
> db.comment.find({"articleid":"100001"},{"articleid":1}).limit(1)
{ "_id" : "1", "articleid" : "100001" }
// 强制_id不显示
> db.comment.find({"articleid":"100001"},{"articleid":1,"_id":0}).limit(1)
{ "articleid" : "100001" }
可以使用 $in
操作符表示范围查询
db.inventory.find( { status: { $in: [ "A", "D" ] } } )
多个查询条件用逗号分隔, 表示 AND
的关系
db.inventory.find( { status: "A", qty: { $lt: 30 } } )
等价于下面 sql 语句
SELECT * FROM inventory WHERE status = "A" AND qty < 30
使用 $or
操作符表示后边数组中的条件是OR的关系
db.inventory.find( { $or: [ { status: "A" }, { qty: { $lt: 30 } } ] } )
等价于下面 sql 语句
SELECT * FROM inventory WHERE status = "A" OR qty < 30
联合使用 AND
和 OR
的查询语句
db.inventory.find( {
status: "A",
$or: [ { qty: { $lt: 30 } }, { item: /^p/ } ]
} )
在 terminal 中查看结果可能不是很方便, 所以我们可以用 pretty()
来帮助阅读
db.inventory.find().pretty()
匹配内容
db.posts.find({
comments: {
$elemMatch: {
user: 'Harry Potter'
}
}
}).pretty()
// 正则表达式
db.<collection_name>.find({ content : /once/ })
创建索引
db.posts.createIndex({
{ title : 'text' }
})
// 文本搜索
// will return document with title "Post One"
// if there is no more posts created
db.posts.find({
$text : {
$search : "\"Post O\""
}
}).pretty()
db.<collection_name>.updateOne(<filter>, <update>, <options>)
方法修改一个匹配 <filter>
条件的文档db.<collection_name>.updateMany(<filter>, <update>, <options>)
方法修改所有匹配 <filter>
条件的文档db.<collection_name>.replaceOne(<filter>, <update>, <options>)
方法替换一个匹配 <filter>
条件的文档db.<collection_name>.update(查询对象, 新对象)
默认情况下会使用新对象替换旧对象其中 <filter>
参数与查询方法中的条件参数用法一致
覆盖修改,会将其他的值清除
// nModified1表示有一条记录被修改
> db.comment.update({"_id":"1"}, {"likenum":NumberInt(1001)})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
// 可以看到其他字段的值不见了
> db.comment.find()
{ "_id" : "1", "likenum" : 1001 }
{ "_id" : "2", "articleid" : "100001", "content" : "我夏天空腹喝凉开水,冬天喝温开水", "userid" : "1005", "nickname" : "伊人憔悴", "createdatetime" : ISODate("2019-08-05T23:58:51.485Z"), "likenum" : 888, "state" : "1" }
{ "_id" : "3", "articleid" : "100001", "content" : "我一直喝凉开水,冬天夏天都喝。", "userid" : "1004", "nickname" : "杰克船长", "createdatetime" : ISODate("2019-08-06T01:05:06.321Z"), "likenum" : 666, "state" : "1" }
{ "_id" : "4", "articleid" : "100001", "content" : "专家说不能空腹吃饭,影响健康。", "userid" : "1003", "nickname" : "凯撒", "createdatetime" : ISODate("2019-08-06T08:18:35.288Z"), "likenum" : 2000, "state" : "1" }
{ "_id" : "5", "articleid" : "100001", "content" : "研究表明,刚烧开的水千万不能喝,因为烫嘴。", "userid" : "1003", "nickname" : "凯撒", "createdatetime" : ISODate("2019-08-06T11:01:02.521Z"), "likenum" : 3000, "state" : "1" }
局部修改,只修改我们修改的部分,其他字段不受影响
如果需要修改指定的属性, 而不是替换需要用“修改操作符”来进行修改
$set
修改文档中的制定属性// 发现局部修改后其他字段并不受影响
> db.comment.update({ "_id": "2" }, {$set:{ "likenum": NumberInt(1001) }})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
> db.comment.find()
{ "_id" : "1", "likenum" : 1001 }
{ "_id" : "2", "articleid" : "100001", "content" : "我夏天空腹喝凉开水,冬天喝温开水", "userid" : "1005", "nickname" : "伊人憔悴", "createdatetime" : ISODate("2019-08-05T23:58:51.485Z"), "likenum" : 1001, "state" : "1" }
{ "_id" : "3", "articleid" : "100001", "content" : "我一直喝凉开水,冬天夏天都喝。", "userid" : "1004", "nickname" : "杰克船长", "createdatetime" : ISODate("2019-08-06T01:05:06.321Z"), "likenum" : 666, "state" : "1" }
{ "_id" : "4", "articleid" : "100001", "content" : "专家说不能空腹吃饭,影响健康。", "userid" : "1003", "nickname" : "凯撒", "createdatetime" : ISODate("2019-08-06T08:18:35.288Z"), "likenum" : 2000, "state" : "1" }
{ "_id" : "5", "articleid" : "100001", "content" : "研究表明,刚烧开的水千万不能喝,因为烫嘴。", "userid" : "1003", "nickname" : "凯撒", "createdatetime" : ISODate("2019-08-06T11:01:02.521Z"), "likenum" : 3000, "state" : "1" }
其中最常用的修改操作符即为$set
和$unset
,分别表示赋值和取消赋值.
db.inventory.updateOne(
{ item: "paper" },
{
$set: { "size.uom": "cm", status: "P" },
$currentDate: { lastModified: true }
}
)
db.inventory.updateMany(
{ qty: { $lt: 50 } },
{
$set: { "size.uom": "in", status: "P" },
$currentDate: { lastModified: true }
}
)
- uses the
$set
operator to update the value of thesize.uom
field to"cm"
and the value of thestatus
field to"P"
,- uses the
$currentDate
operator to update the value of thelastModified
field to the current date. IflastModified
field does not exist,$currentDate
will create the field. See$currentDate
for details.
db.<collection_name>.replaceOne()
方法替换除 _id
属性外的所有属性, 其<update>
参数应为一个全新的文档.
db.inventory.replaceOne(
{ item: "paper" },
{ item: "paper", instock: [ { warehouse: "A", qty: 60 }, { warehouse: "B", qty: 40 } ] }
)
批量修改
在后面添加{multi: true}
即可
// 默认会修改第一条
db.commnet.update({ userid: "30", { $set {username: "guest"} } })
// 修改所有符合条件的数据
db.commnet.update( { userid: "30", { $set {username: "guest"} } }, {multi: true} )
列值增长的修改
如果我们想实现对某列值在原有值的基础上进行增加或减少, 可以使用 $inc
运算符来实现
db.commnet.update({ _id: "3", {$inc: {likeNum: NumberInt(1)}} })
修改操作符
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. |
db.collection.remove()
通过添加删除规则进行删除db.collection.deleteMany()
方法删除所有匹配的文档.db.collection.deleteOne()
方法删除单个匹配的文档.db.collection.drop()
db.dropDatabase()
只删除一条记录
如果不加后面的限制会删除所有匹配的记录
以下语句可以将数据全部删除,请慎用
db.comment.remove({})
Delete operations do not drop indexes, even if deleting all documents from a collection.
一般数据库中的数据都不会真正意义上的删除, 会添加一个字段, 用来表示这个数据是否被删除
在查询文档内容的时候, 默认是按照 _id
进行排序
我们可以用 $sort
更改文档排序规则
{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }
For the field or fields to sort by, set the sort order to 1
or -1
to specify an ascending or descending sort respectively, as in the following example:
db.users.aggregate(
[
{ $sort : { age : -1, posts: 1 } }
// ascending on posts and descending on age
]
)
$sort
Operator and Memory
$sort
+ $limit
Memory Optimization
When a $sort
precedes a $limit
and there are no intervening stages that modify the number of documents, the optimizer can coalesce the $limit
into the $sort
. This allows the $sort
operation to only maintain the top n
results as it progresses, where n
is the specified limit, and ensures that MongoDB only needs to store n
items in memory. This optimization still applies when allowDiskUse
is true
and the n
items exceed the aggregation memory limit.
Optimizations are subject to change between releases.
有点类似于用 heap 做 topK 这种问题, 只维护 k 个大小的 heap, 会加速 process
举个栗子:
db.posts.find().sort({ title : -1 }).limit(2).pretty()
有些情况, 我们对文档进行查询并不是需要所有的字段, 比如只需要 id 或者 用户名, 我们可以对文档进行“投影”
1
- display0
- dont display> db.users.find( {}, {username: 1} )
> db.users.find( {}, {age: 1, _id: 0} )
统计查询使用count()方法,语法如下:
db.collection.count(query, options)
参数:
提示: 可选项暂时不使用。
【示例】
(1)统计所有记录数: 统计comment集合的所有的记录数:
(2)按条件统计记录数:例如:统计userid为1003的记录条数
提示: 默认情况下 count() 方法返回符合条件的全部记录条数。
可以使用limit()方法来读取指定数量的数据,使用skip()方法来跳过指定数量的数据
基本语法如下所示:
db.COLLECTION_NAME.find().limit(NUMBER).skip(NUMBER)
sort() 方法对数据进行排序,sort() 方法可以通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而 -1 是用 于降序排列。
语法如下所示:
db.COLLECTION_NAME.find().sort({KEY:1})
或
db.集合名称.find().sort(排序方式)
例如: 对userid降序排列,并对访问量进行升序排列
提示: skip(), limilt(), sort()三个放在一起执行的时候,执行的顺序是先 sort(), 然后是 skip(),最后是显示的 limit(),和命令编写顺序无关。
MongoDB的模糊查询是通过正则表达式的方式实现的。格式为
$ db.collection.find({field:/正则表达式/})
$ db.collection.find({字段:/正则表达式/})
提示:正则表达式是js的语法,直接量的写法。 例如,我要查询评论内容包含“开水”的所有文档,代码如下:
如果要查询评论的内容中以“专家”开头的,代码如下:
附录:常用的正则表达式
<
, <=
, >
, >=
这些操作符也是很常用的, 格式如下:
其实这些字符就是对应JS里面的:gt(great than)、lt(less than)、gte(great than equal )、lte(less than equal )、ne(not equal)
db.collection.find({ "field" : { $gt: value }}) // 大于: field > value
db.collection.find({ "field" : { $lt: value }}) // 小于: field < value
db.collection.find({ "field" : { $gte: value }}) // 大于等于: field >= value
db.collection.find({ "field" : { $lte: value }}) // 小于等于: field <= value
db.collection.find({ "field" : { $ne: value }}) // 不等于: field != value
示例:查询评论点赞数量大于700的记录
包含使用 $in
操作符. 示例:查询评论的集合中 userid
字段包含 1003
或 1004
的文档
db.comment.find({userid:{$in:["1003","1004"]}})
不包含使用 $nin
操作符. 示例:查询评论集合中 userid
字段不包含 1003
和 1004
的文档
db.comment.find({userid:{$nin:["1003","1004"]}})
我们如果需要查询同时满足两个以上条件,需要使用$and操作符将条件进行关联。(相当于SQL的and) 格式为:
$and:[ { },{ },{ } ]
示例:查询评论集合中likenum大于等于700 并且小于2000的文档:
db.comment.find({$and:[{likenum:{$gte:NumberInt(700)}},{likenum:{$lt:NumberInt(2000)}}]})
如果两个以上条件之间是或者的关系,我们使用 操作符进行关联,与前面 and的使用方式相同 格式为:
$or:[ { },{ },{ } ]
示例:查询评论集合中userid为1003,或者点赞数小于1000的文档记录
db.comment.find({$or:[ {userid:"1003"} ,{likenum:{$lt:1000} }]})
我们知道这些查询语句其实就是js
的语法格式,所有在查询得到结果后我们也可以通过forEach
函数对结果进行遍历
db.posts.find().forEach(
fucntion(doc) {
print('Blog Post: ' + doc.title)
})
// 也可以通过箭头函数简化一下
db.comment.find().forEach((it)=> {
print(it._id)
});
请查看MongoDB中文文档:地理空间查询 - MongoDB-CN-Manual (mongoing.com)
选择切换数据库:use articledb 插入数据:db.comment.insert({bson数据}) 查询所有数据:db.comment.find(); 条件查询数据:db.comment.find({条件}) 查询符合条件的第一条记录:db.comment.findOne({条件}) 查询符合条件的前几条记录:db.comment.find({条件}).limit(条数) 查询符合条件的跳过的记录:db.comment.find({条件}).skip(条数) 修改数据:db.comment.update({条件},{修改后的数据}) 或 db.comment.update({条件},{$set:{要修改部分的字段:数据}) 修改数据并自增某字段值:db.comment.update({条件},{$inc:{自增的字段:步进值}}) 删除数据:db.comment.remove({条件}) 统计查询:db.comment.count({条件}) 模糊查询:db.comment.find({字段名:/正则表达式/}) 条件比较运算:db.comment.find({字段名:{$gt:值}}) 包含查询:db.comment.find({字段名:{$in:[值1, 值2]}}) 或 db.comment.find({字段名:{$nin:[值1, 值2]}}) 条件连接查询:db.comment.find({$and:[{条件1},{条件2}]}) 或 db.comment.find({$or:[{条件1},{条件2}]})
在MongoDB中可以通过内嵌文档的形式体现出一对一的关系,比如夫妻:
{
name:'黄蓉',
husband:{
name:'郭靖'
}
}
一个文档对象一旦被嵌入到另一个文档对象中就绝不可能再被嵌入到其他文档对象中,因此可以体现出一对一的关系
一对多的关系在实际开发中是非常常用的,也是现实世界中出现频率比较高的关系
有两种方式可以体现一对多(或多对一)的关系,以客户和订单为例:
一:关系在一的一方维护,直接通过内嵌数组,在数组中存放整个对象的方式:这种方式不好,因为如果对应的对象比较多的话,文档就会看起来很复杂,不易查询
{ cust_id:ObjectId("5d272c817f2dc9e6986d82fb"), cust_name:"黑宋江", orders:[ { _id: ObjectId("5d2614c42b1a4fdfd82bfda3"), type:"牛肉", count:2 }, { _id:ObjectId("5d272c817f2dc9e6986d82fa"), type:"酒", count:6 } ] }
二:一对多,用户:constom/订单orders
举个例子, 比如“用户-订单”这个一对多的关系中, 我们想查询某一个用户的所有或者某个订单, 我们可以在用户中添加订单的主键
先创建用户集合
db.constom.insert([
{username:'孙悟空'},
{username:'猪八戒'}
])
再创建订单集合(添加一个userid属性,该订单是谁的就给userid属性添加谁的_id)
db.orders.insert({
list:["辣椒","花椒","油"],
userid:ObjectId("5ebcfe39bc5756d0fed31ff3")//这个是孙悟空的_id代表该订单就是孙悟空的。
})
通过userid再去查找每个人对应的订单
var userid = db.constom.findOne({username:'孙悟空'})._id;
db.orders.find({userid:userid})
在关系型数据库中我们处理多对多关系的时候采用的方法一般是将两张表的主键抽取出来,放到一张单独的关系表中,将两张表的主键作为这张关系表的外键,每次做关联查询的时候都要先到这张关系表中找出对应表的主键
在MongoDB中多对多采用的其实是类似与一对多
的情况,也是通过增加一些冗余的字段
来记录关系
举个例子,我们在关系型数据库中一般会以学生和老师作为例子,这里同样我们也举这个:
//多对多 // 先插入一些老师的信息 db.teachers.insertMany([ {name:"洪七公"}, {name:"黄药师"}, {name:"龟仙人"} ]); db.teachers.find(); // 插入一些学生的信息,并且将老师的id进行记录 db.students.insertMany([ { name:"郭靖", teachers_ids:[ ObjectId("5d7f018b162f56aeed8aedda"), ObjectId("5d7f018b162f56aeed8aeddb"), ObjectId("5d7f018b162f56aeed8aeddc") ] },{ name:"黄蓉", teachers_ids:[ ObjectId("5d7f018b162f56aeed8aedda"), ObjectId("5d7f018b162f56aeed8aeddb"), ObjectId("5d7f018b162f56aeed8aeddc") ] } ]); db.students.find();
索引支持在 MongoDB 中高效地执行查询.如果没有索引, MongoDB 必须执行全集合扫描, 即扫描集合中的每个文档, 以选择与查询语句 匹配的文档.这种扫描全集合的查询效率是非常低的, 特别在处理大量的数据时, 查询可以要花费几十秒甚至几分钟, 这对网站的性能是非常致命的.
如果查询存在适当的索引, MongoDB 可以使用该索引限制必须检查的文档数.
索引是特殊的数据结构, 它以易于遍历的形式存储集合数据集的一小部分.索引存储特定字段或一组字段的值, 按字段值排序.索引项的排 序支持有效的相等匹配和基于范围的查询操作.此外, MongoDB 还可以使用索引中的排序返回排序结果.
MongoDB 和MySQL 一样使用的都是是 B+ Tree
在之前的版本中Mongo使用的是B树,但是现在都是使用B+树了
索引常用命令:
// create index db.<collection_name>.createIndex({ userid : 1, username : -1 }) // retrieve indexes db.<collection_name>.getIndexes() // remove indexes db.<collection_name>.dropIndex(index) // there are 2 ways to remove indexes: // 1. removed based on the index name // 2. removed based on the fields db.<collection_name>.dropIndex( "userid_1_username_-1" ) db.<collection_name>.dropIndex({ userid : 1, username : -1 }) // remove all the indexes, will only remove non_id indexes db.<collection_name>.dropIndexes()
MongoDB 支持在文档的单个字段上创建用户定义的升序/降序索引, 称为单字段索引(Single Field Index)
对于单个字段索引和排序操作, 索引键的排序顺序(即升序或降序)并不重要, 因为 MongoDB 可以在任何方向上遍历索引.
MongoDB 还支持多个字段的用户定义索引, 即复合索引 Compound Index,这个其实非常类似MySQL
中的联合索引,因为底层都是B+树,所有联合索引可能也有最左原则
这种东西
复合索引中列出的字段顺序具有重要意义.例如, 如果复合索引由 { userid: 1, score: -1 }
组成, 则索引首先按 userid
正序排序, 然后 在每个 userid
的值内, 再在按 score
倒序排序.
为了支持对地理空间坐标数据的有效查询, MongoDB 提供了两种特殊的索引: 返回结果时使用平面几何的二维索引和返回结果时使用球面几何的二维球面索引.
MongoDB 提供了一种文本索引类型, 支持在集合中搜索字符串内容.这些文本索引不存储特定于语言的停止词(例如 “the”, “a”, “or”), 而将集合中的词作为词干, 只存储根词.
为了支持基于散列的分片, MongoDB 提供了散列索引类型, 它对字段值的散列进行索引.这些索引在其范围内的值分布更加随机, 但只支持相等匹配, 不支持基于范围的查询.
语法
db.collection.getIndexes()
提示:该语法命令运行要求是MongoDB 3.0+
【示例】 查看comment集合中所有的索引情况
结果中显示的是默认 _id 索引。
默认 _id
索引: MongoDB 在创建集合的过程中, 在 _id
字段上创建一个唯一的索引, 默认名字为 _id
, 该索引可防止客户端插入两个具有相同值的文 档, 不能在 _id
字段上删除此索引.
注意:该索引是唯一索引, 因此值不能重复, 即 _id
值不能重复的.
在分片集群中, 通常使用 _id
作为片键.
语法
db.collection.createIndex(keys, options)
参数
options(更多选项)列表
注意在 3.0.0 版本前创建索引方法为 db.collection.ensureIndex()
, 之后的版本使用了 db.collection.createIndex()
方法, ensureIndex()
还能用, 但只是 createIndex()
的别名.
举个
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。