MongoDB
MongoDB是一个提供了高性能、高可用及自动伸缩功能的开源的文档数据库(Document Database),由C++语言编写。旨在为web应用提供可扩展的高性能数据存储解决方案
文档数据库
在MongoDB中一条记录就是一个文档,文档本身类似于JSON对象,其数据结构是组合的键值对。
文档的优势在于:
1) 文档可以对应到许多编程语言内置的数据类型
2) 内嵌的文档和数组结构减少了跨表查询
3) 自由的表结构支持流畅的多态
MongoDB特点
1、模式自由:可以把不同结构的文档存储在同一个数据库里
2、面向集合的存储:适合存储JSON风格文件的形式
3、完整的索引支持:对任何属性可索引
4、复制和高可用:支持服务器间的数据复制,支持主-从模式
5、自动分片:自动分片功能支持水平的数据库集群,可动态添加额外的机器
6、丰富的查询:支持丰富的查询表达式,查看指令使用JSON形式的标记,可轻易查询文档中的内嵌对象及数组
7、快速就地更新:查询优化器会分析查询表达式,并生成一个高效的查询计划
8、高效的传统存储方式:支持二进制数据及大型对象(如照片或图片)
MongoDB基本概念
1、数据库 database
2、集合 collection,类似于数据表
3、文档 document, 类似于记录
4、字段 field,类似于字段
配置文件其他选项说明 :
数据库基本操作
1、查看数据库
> show dbs
admin 0.000GB
local 0.000GB
2、查看当前数据库
> db
game
> db.getName()
game
3、创建数据库
> use <db_name>
数据库如果存在,则为切换数据库,否则为创建数据库
> use game
switched to db game
> show dbs
admin 0.000GB
local 0.000GB
此时使用show dbs命令查看不到game库,因为game库中没有数据;可通过以下方式在game库中创建一个集合tb01
> use game
switched to db game
> db.createCollection("tb01")
{ "ok" : 1 }
> show dbs
admin 0.000GB
game 0.000GB
local 0.000GB
4、删除当前使用的数据库
> db.dropDatabase()
{ "dropped" : "game", "ok" : 1 }
> show dbs
admin 0.000GB
local 0.000GB
5、查看当前数据库状态
> db.stats()
{
"db" : "game",
"collections" : 1,
"views" : 0,
"objects" : 0,
"avgObjSize" : 0,
"dataSize" : 0,
"storageSize" : 4096,
"numExtents" : 0,
"indexes" : 1,
"indexSize" : 4096,
"ok" : 1
}
6、显示数据库版本
> db.version()
3.4.3
7、查看数据库当前监听地址
> db.getMongo()
connection to 127.0.0.1:27017
集合collection相关操作
1、查看数据库中的集合
> use game
switched to db game
> show collections
tb01
2、创建集合
语法:
db.createCollection(name, { size : ..., capped : ..., max : ... } )
name:集合名称
capped:指定为true时,表示创建上限集合(即当集合中文档数量达到一定量时,会覆盖旧的文档),此参数为true时,需要指定size参数
size:指定该集合中文档的大小,以Byte为单位
max:指定该集合中最大文档数量
> db.createCollection("tb02")
{ "ok" : 1 }
> db.createCollection("tb03",{capped: true, size: 100000, max: 10000})
{ "ok" : 1 }
> show collections
tb01
tb02
tb03
向一个不存在的集合中插入文档时,也会自动创建该集合
> db.tb04.insert({"name": "martin", "age": 20})
> show collections
tb01
tb02
tb03
tb04
3、获取指定名称的集合
> db.getCollection("tb01")
game.tb01
> db.getCollection("tb02")
game.tb02
4、查看当前数据库中所有集合名称
> db.getCollectionNames()
[ "tb01", "tb02", "tb03", "tb04" ]
5、删除集合
> db.tb01.drop()
true
> db.tb02.drop()
true
文档增、删、改、查
MongoDB支持许多数据类型
字符串 - 这是用于存储数据的最常用的数据类型。MongoDB中的字符串必须为UTF-8。
整型 - 此类型用于存储数值。 整数可以是32位或64位,具体取决于服务器。
布尔类型 - 此类型用于存储布尔值(true / false)值。
双精度浮点数 - 此类型用于存储浮点值。
最小/最大键 - 此类型用于将值与最小和最大BSON元素进行比较。
数组 - 此类型用于将数组或列表或多个值存储到一个键中。
时间戳 - ctimestamp,当文档被修改或添加时,可以方便地进行录制。
对象 - 此数据类型用于嵌入式文档。
对象 - 此数据类型用于嵌入式文档。
Null - 此类型用于存储Null值。
符号 - 该数据类型与字符串相同; 但是,通常保留用于使用特定符号类型的语言。
日期 - 此数据类型用于以UNIX时间格式存储当前日期或时间。您可以通过创建日期对象并将日,月,年的日期进行指定自己需要的日期时间。
对象ID - 此数据类型用于存储文档的ID。
二进制数据 - 此数据类型用于存储二进制数据。
代码 - 此数据类型用于将JavaScript代码存储到文档中。
正则表达式 - 此数据类型用于存储正则表达式。
1、插入文档
语法1):
> db.<collection_name>.insert(document)
示例:
> db.tb01.insert({id:001, name: "martin", description: "test"})
WriteResult({ "nInserted" : 1 })
> db.tb01.insert({
... _id: 100,
... title: "MongoDB Overview",
... description: "MongoDB is no sql database",
... by: "martin",
... url: "www.martin.com",
... tags: ["mongodb","database","NoSQL"],
... likes: 100
... })
WriteResult({ "nInserted" : 1 })
>
在插入文档时如果不指定_id,则mongoDB会为此文档生成一个唯一的objectID
同时插入多个文档
> db.tb01.insert([
... {
... _id: 101,
... title: "MongoDB Guide",
... description: "MongoDB is no sql database",
... by: "martin",
... url: "www.martin.com",
... tags: ["mongodb","database","NoSQL"],
... likes: 100
... },
...
... {
... _id: 102,
... title: "NoSQL Database",
... description: "NoSQL database doesn't have tables",
... by: "martin",
... url: "www.martin.com",
... tags: ["mongodb","database","NoSQL"],
... likes: 210,
... comments: [
... {
... user: "user1",
... message: "My first comment",
... dateCreated: new Date(2017,12,5,19,24),
... like: 0
... }
... ]
... },
...
... {
... _id: 103,
... title: "Python Quick Guide",
... description: "Python Quick start",
... by: "martin",
... url: "www.martin.com",
... tags: ["Python","database","NoSQL"],
... likes: 30,
... comments: [
... {
... user: "user1",
... message: "My first comment",
... dateCreated: new date(2018,11,10,2,35),
... like: 580
... }
... ]
... }
... ])
语法2):
> db.collection_name.insertOne(document)
此方法会返回一个插入文档的ObjectID
示例:
> db.inventory.insertOne(
... { item: "canvas", qty: 100, tags: ["cotton"], size: { h: 28, w: 35.5, uom: "cm" }}
... )
{
"acknowledged" : true,
"insertedId" : ObjectId("5a2683e4b4720e8514e971a1")
}
语法3):
> db.collection_name.insertMany(document)
此方法会返回文档的objectID
> db.inventory.insertMany([
... { item: "journal", qty: 25, tags: ["blank","red"], size: {h: 14, w: 21, uom: "cm"}},
... { item: "mat", qty: 85, tags: ["gray"], size: {h: 27.9, w: 35.5, uom: "cm"}},
... { item: "mousepad", qty: 25, tags: ["gel", "blue"], size: {h: 19, w: 22.85, uom: "cm"}}
... ])
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("5a2684d6b4720e8514e971a2"),
ObjectId("5a2684d6b4720e8514e971a3"),
ObjectId("5a2684d6b4720e8514e971a4")
]
}
>
查询文档
语法:
> db.collection_name.find()
该方法以非结构化的方式显示所有数据,如果想使用结构化方式显示数据,需要使用pretty()方法
> db.collection_name.find().pretty()
> db.tb01.find().pretty()
mongodb比较运算符的使用:
1、{<key>: <value>} 等于
> db.tb01.find(
... { _id: 103 }
... ).pretty()
2、{<key>: {$lt:<value>}} 小于
> db.tb01.find(
... {_id: {$lt: 102}}
... ).pretty()
3、{<key>: {$lte:<value>}} 小于等于
> db.tb01.find(
... {_id: {$lte: 102}}
... ).pretty()
4、{<key>: {$gt:<value>}} 大于
> db.tb01.find(
... {_id: {$gt: 102}}
... ).pretty()
5、{<key>: {$gte:<value>}} 大于等于
> db.tb01.find(
... { _id: {$gte: 102} }
... ).pretty()
6、{<key>: {$ne:<value>}} 不等于
> db.tb01.find(
... {_id: {$ne: 102}}
... ).pretty()
逻辑运算符的使用
1、AND
语法:
> db.collection_name.find(
{
$and: [
{key: value}, {key: value}
]
}
)
> db.tb01.find(
... {
... $and: [
... { by: "martin" }, { title: "MongoDB Overview" }
... ]
... }
... ).pretty()
{
"_id" : 100,
"title" : "MongoDB Overview",
"description" : "MongoDB is no sql database",
"by" : "martin",
"url" : "www.martin.com",
"tags" : [
"mongodb",
"database",
"NoSQL"
],
"likes" : 100
}
>
2、OR
语法:
> db.collection_name.find(
{
$or: [
{key: value}, {key: value}
]
}
)
> db.tb01.find(
... {
... $or: [
... { title: "MongoDB Overview" }, { title: "MongoDB Guide" }
... ]
... }
... ).pretty()
3、AND/OR同时使用
> db.tb01.find(
... {
... by: "martin",
... $or: [
... { title: "MongoDB Overview" }, { title: "MongoDB Guide" }
... ]
... }
... ).pretty()
显示指定字段的数据(投影)
> db.collection_name.find({},{key:1,key:1,...})
MongoDB的find()方法,其中第二个参数表示显示指定字段的数据,其中上述格式中key为指定的字段名称,值为1表示仅显示该字段的数据
> db.inventory.find({},{_id:1, item:1})
{ "_id" : ObjectId("5a2683e4b4720e8514e971a1"), "item" : "canvas" }
{ "_id" : ObjectId("5a2684d6b4720e8514e971a2"), "item" : "journal" }
{ "_id" : ObjectId("5a2684d6b4720e8514e971a3"), "item" : "mat" }
{ "_id" : ObjectId("5a2684d6b4720e8514e971a4"), "item" : "mousepad" }
{ "_id" : ObjectId("5a268f122b720c3680067af1"), "item" : "journal" }
find()方法总是显示_id字段的数据,如果不想显示_id字段的数据,则需要把_id设置为0
> db.inventory.find({},{_id:0, item:1})
{ "item" : "canvas" }
{ "item" : "journal" }
{ "item" : "mat" }
{ "item" : "mousepad" }
{ "item" : "journal" }
限制显示文档的数量
limit(number)方法
限制 MongoDB 中返回的记录数,需要使用limit()方法。
该方法接受一个数字类型参数,它表示要显示的文档数。
示例:显示结果集的前三行记录
> db.inventory.find({},{_id:0, item:1}).limit(3)
{ "item" : "canvas" }
{ "item" : "journal" }
{ "item" : "mat" }
>
skip(number)方法
skip()表示要跳过的记录数量
示例:跳过结果集的前三行不显示
> db.inventory.find({},{_id:0, item:1}).skip(3)
{ "item" : "mousepad" }
{ "item" : "journal" }
{ "item" : "notebook" }
{ "item" : "paper" }
{ "item" : "planner" }
{ "item" : "postcard" }
示例:仅显示第三行记录
> db.inventory.find({},{_id:0, item:1}).skip(2).limit(1)
{ "item" : "mat" }
>
按字段排序显示数据
排序显示数据需要使用sort()方法,语法如下:
> db.collection_name.find().sort({key:1})
其中sort({key:1}),1表示升序,-1表示降序
示例:按item字段升序显示数据
> db.inventory.find({},{_id:1, item: 1}).sort({item:1})
{ "_id" : ObjectId("5a2683e4b4720e8514e971a1"), "item" : "canvas" }
{ "_id" : ObjectId("5a2684d6b4720e8514e971a2"), "item" : "journal" }
{ "_id" : ObjectId("5a268f122b720c3680067af1"), "item" : "journal" }
{ "_id" : ObjectId("5a2684d6b4720e8514e971a3"), "item" : "mat" }
{ "_id" : ObjectId("5a2684d6b4720e8514e971a4"), "item" : "mousepad" }
示例:按item字段降序显示数据
> db.inventory.find({},{_id:1, item:1}).sort({item:-1})
{ "_id" : ObjectId("5a268f122b720c3680067af5"), "item" : "postcard" }
{ "_id" : ObjectId("5a268f122b720c3680067af4"), "item" : "planner" }
{ "_id" : ObjectId("5a268f122b720c3680067af3"), "item" : "paper" }
{ "_id" : ObjectId("5a268f122b720c3680067af2"), "item" : "notebook" }
{ "_id" : ObjectId("5a2684d6b4720e8514e971a4"), "item" : "mousepad" }
{ "_id" : ObjectId("5a2684d6b4720e8514e971a3"), "item" : "mat" }
聚合运算操作
示例01:按by_user字段进行分组,并对出现的用户进行+1操作
> db.article.aggregate(
... [
... { $group: {_id: "$by_user", number: {$sum: 1}} }
... ]
... )
{ "_id" : "Curry", "number" : 1 }
{ "_id" : "Kuber", "number" : 1 }
{ "_id" : "Maxsu", "number" : 2 }
示例02:按by_user进行分组, 并对字段likes进行平均值运算
> db.article.aggregate(
... [
... { $group: {_id: "$by_user", number: {$avg: "$likes"}} }
... ]
... )
{ "_id" : "Curry", "number" : 350 }
{ "_id" : "Kuber", "number" : 750 }
{ "_id" : "Maxsu", "number" : 55 }
>
示例03:按by_user进行分组,并对字段likes计算最小值
> db.article.aggregate(
... [
... { $group: {_id: "$by_user", number: {$min: "$likes"}} }
... ]
... )
{ "_id" : "Curry", "number" : 350 }
{ "_id" : "Kuber", "number" : 750 }
{ "_id" : "Maxsu", "number" : 10 }
>
示例04:按by_user进行分组, 并对字段likes计算最大值
> db.article.aggregate(
... [
... { $group: { _id: "$by_user", number: {$max: "$likes"}} }
... ]
... )
{ "_id" : "Curry", "number" : 350 }
{ "_id" : "Kuber", "number" : 750 }
{ "_id" : "Maxsu", "number" : 100 }
>
示例05:按name字段进行分组,获取url字段中的第一行记录
> db.test.aggregate(
... [
... { $group: {_id: "$name", first_url: {$first: "$url"}} }
... ]
... )
{ "_id" : "tom", "first_url" : "www.d.org" }
{ "_id" : "jerry", "first_url" : "www.c.org" }
{ "_id" : "martin", "first_url" : "www.a.org" }
示例06:按name字段进行分组,获取url字段中最后一行记录
> db.test.aggregate(
... [
... { $group: {_id: "$name", last_url: {$last: "$url"}} }
... ]
... )
{ "_id" : "tom", "last_url" : "www.d.org" }
{ "_id" : "jerry", "last_url" : "www.c.org" }
{ "_id" : "martin", "last_url" : "www.b.org" }
>
示例07:按name字段进行分组,并将url字段的值以数组的方式显示,重复项会多次显示
> db.test.aggregate(
... [
... { $group: {_id: "$name", new_url: {$push: "$url"}} }
... ]
... )
{ "_id" : "tom", "new_url" : [ "www.d.org" ] }
{ "_id" : "jerry", "new_url" : [ "www.c.org" ] }
{ "_id" : "martin", "new_url" : [ "www.a.org", "www.b.org", "www.a.org" ] }
>
示例08:按name字段进行分组,并将url字段的值以数组的方式显示,重复项仅会显示一次
> db.test.aggregate(
... [
... { $group: {_id: "$name", new_url: {$addToSet: "$url"}} }
... ]
... )
{ "_id" : "tom", "new_url" : [ "www.d.org" ] }
{ "_id" : "jerry", "new_url" : [ "www.c.org" ] }
{ "_id" : "martin", "new_url" : [ "www.b.org", "www.a.org" ] }
>
更新文档
mongodb更新文档可使用update()方法或者save()方法
update()方法用于更新现有文档中的值
save()方法用于替换现有文档
> db.tb01.update({ title: "MongoDB Overview" },
... {$set: { title: "New Update MongoDB Overview" }})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
>
update()方法一次只更新一个文档,如需更新多个,则需要将参数multi设置为true
> db.tb01.update(
... { url: "www.martin.com" },
... { $set: {url: "http://www.martin.com"} },
... { multi: true }
... )
WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 3 })
>
>
save()方法直接替换文档
> db.tb01.save(
... {
... _id: 100, title: "Updated by save() method", by: "martin"
... }
... )
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.tb01.save(
... {
... title: "MongoDB Guide", by: "jerry"
... }
... )
WriteResult({ "nInserted" : 1 })
删除文档
语法:
> db.collection_name.remove(conditon, justOne=true)
justOne:表示只删除一条数据
示例01: 删除作者为martin的文档
> db.tb01.remove({ by: "martin" })
WriteResult({ "nRemoved" : 4 })
>
> db.tb01.find({ by: "martin" }).pretty()
>
示例02:仅删除名称为martin的一条数据
> db.tb01.remove(
... { name: "martin" },
... { justOne: true}
... )
示例03:删除所有文档
> db.tb01.remove( {}, {justOne: false})
WriteResult({ "nRemoved" : 2 })
> db.tb01.find().pretty()
>