Eli's Blog

1. 基本概念

  • 面向集合(Collection-Oriented):
    数据存储在集合中,每个集合在数据库中都有唯一的标识名,可以包含无限数量的文档

  • 模式自由(Schema-Free):
    集合类似RMDB中的Table,但无Schema

  • 文档型(Document File):
    存储数据是键值对的集合”JSON”,键是字符串,值可以是任意类型。存储数据类型称为BSON(Binary Serialized Document Notation)

1.1 数据逻辑结构

  • 文档(document): RMDB中的行
  • 集合(collection): RMDB中的表,由多个文档构成
  • 数据库(database): 与RMDB一致

2. 相关命令

2.1 查看帮助

1
2
3
help
db.help()
db.account.help()

2.2 数据库管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
show dbs
use mydb

db.copyDatabase('mydb', 'temp', '127.0.0.1')
db.cloneDatabase('10.137.5.44')

use temp
db.dropDatabase() # 删当前数据库

db.repairDatabase()

db.getName() # 当前数据库名

db.getMongo() # 服务器地址

db.stats()
db.version()

use admin
db.shutdownServer()

2.3 集合操作

1
2
3
4
5
6
7
8
9
10
db.createCollection('account', {size:20, capped:5, max:100})
db.getCollection('account')
db.getCollectionNames()

db.account.help()
db.account.count()
db.account.dataSize()
db.account.totalSize()
db.account.getDB()
db.account.renameCollection('accounts')

2.4 用户管理

1
2
3
4
5
6
7
8
9
show roles
db.createUser(
{
user: 'eli',
pwd: '123',
roles: [{role: 'userAdmin', db: 'mydb'}]
})

db.auth('eli', '123')

2.5 增删改查

1
2
3
4
5
db.account.save({name: 'mongo'})
db.account.insert({x:1})
db.account.find({name: 'mongo'})
db.account.update({name: 'mongo'}, {$set, {name: 'new_mongo'}})
db.account.remove({name: 'new_mongo'})
  • update语法:
1
2
3
4
5
6
db.collection.update(  
<query>,
<update>,
upsert:<boolean>,
multi:<boolean> // 默认只修改一条数据
)

更新操作:

———|————–|
名称 |描述|
———|————–|
$inc |根据要添加的值递增该字段的值。|
$mul |将该字段的值乘以指定的值|
$rename |重命名字段|
$setOnInsert |操作时,操作给相应的字段赋值|
$set |用来指定一个键的值,如果不存在则创建它|
$unset |用来指定一个键的值,如果不存在不创建创建它|
$min |只有当指定的值小于现有字段值时才更新该字段。|
$max |只有当指定的值大于现有字段值时才更新该字段。|
$currentDate |设置当前日期字段的值,或者作为一个日期或时间戳。|

3. 查询操作

1
2
3
4
5
db.test.insert({name:'jack', age:29, gender:'male', email:'jack@outlook.com'})
db.test.insert({name:'lucy', age:21, gender:'female', email:'lucy@gmail.com'})
db.test.insert({name:'tom', age:30, gender:'male', email:'tom@abc.com'})
db.test.insert({name:'bonnie', age:29, gender:'female', email:'bonnie@abc.com'})
db.test.insert({name:'jack', age:25, gender:'male', email:'jack@hotmail.com'})

3.1 基本查询

1
2
3
4
5
6
7
db.test.find()             # all
db.test.findOne(). # just one
db.test.find({name:'jack'})
db.test.find({name:'jack', age:29})

db.test.find({}, {name:1, gender:1}) # 只返回name, gender字段
db.test.find({}, {email:0}) # 不返回email字段

3.2 条件查询($gt, $lt, $gte, $lte, $ne, $or, $in, $nin)

1
2
3
4
5
6
7
8
9
db.test.find({age: {$gt: 25, $lt: 30}})
db.test.find({gender: {$ne: 'male'}})
db.test.find({age: {$in: [21, 30]}})
db.test.find({age: {$nin: [21, 30]}})
db.test.find({name: {$not: {$in: ['jack', 'lily']}}})
db.test.find({age: {$mod: [10,1]}})
db.test.find({name: {$exists: true}})

db.test.find({$or: [{name:'jack'}, {name:'tom'}])

3.3 null类型查询

1
2
3
4
5
db.test.update({name:'jack'}, {$set: {addr: null}})
db.test.update({name:'tom'}, {$set: {addr: {city:'NJ', prov:'JS'}}})

db.test.find({addr: null})
db.test.find({addr: {$in: [null], $exists: true}})

3.4 正则表达式

1
2
db.test.find({name:/Jack?/i})
db.test.find({name: {$not: /^b.*/}}) # not like 'b%'

3.5 js和$where查询

1
2
3
4
5
6
db.test.find({age: {$lt: 30}})
db.test.find({$where: "this.age > 30"})
db.test.find("this.age > 30")

f = function() {return this.age>30;}
db.test.find(f)

3.6 count, limit, skip, sort

1
2
3
4
db.test.find().count()
db.test.find().limit(5)
db.test.find().skip(3).limit(5)
db.test.find().sort({age:-1})

3.7 数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
db.fruits.insert({fruit: ['apple', 'orange', 'peach']})
db.fruits.insert({fruit: ['apple', 'kuaquat', 'blueberry']})
db.fruits.insert({fruit: ['pear', 'strawberry', 'banana']})

db.fruits.find({fruit: 'apple'})
db.fruits.find({fruit: {$in: ['apple']}}) # same as above

db.fruits.find({fruit: {$all: ['apple', 'orange']}})

db.fruits.find({fruit: ['apple', 'orange', 'peach']})

db.fruits.find({'fruit.2': 'peach'})

db.fruits.find({fruit: {$size: 3}})

db.fruits.update({}, {$set: {size:3}}, false, true)
db.fruits.find()

db.fruits.update({}, {$push: {fruit:'grape'}, $inc: {size:1}})

db.fruits.find({}, {fruit: {$slice:2}, size: 0})
db.fruits.find({}, {fruit: {$slice:-2}, size: 0})
db.fruits.find({}, {fruit: {$slice:[2,1]}, size: 0})

3.8 查询组合条件

3.8.1 $in

满足列表中任意一个值

1
db.funds.find({'Fee': {'$in': [15, 21]}})

3.8.2 $all

满足列表中全部值

1
db.funds.find({'Fee': {'$all': [15, 21]}})

3.8.3 $or

1
db.funds.find({'$or': [{'Fee': 15}, {'Fee': 21}]})

3.8.4 $and

1
db.funds.find({'$and': [{'Fee': 15}, {'Fee': 21}]})

3.8.5 $exist

节点存在,不关心值是否为null

1
db.test.find({"Fee": {'$exists': true}})

节点不存在或者节点存在但值为null

1
db.test.find({"Fee": null})

3.8.6 $ne

1
db.test.find({"Fee": {'$ne': 21}})
1
{'$and': ["BasicInfo.offshoreFund": {'$in': ["0", "1", "2", "3"]}, "BasicInfo.cayman": {'$in': ["0", "1", "2", "3"]}, "BasicInfo.America": {'$in': ["0", "1", "2"]}, "BasicInfo.BVI": {'$in': ["0", "1", "2", "3"]}]}
1
2
3
4
5
6
db.funds.find({ 
'$and': [
"BasicInfo.America": {'$in': ["0", "1", "2"]},
"BasicInfo.BVI": {'$in': ["0", "1", "2", "3"]}
]
}).count()

3.9 聚合查询

1
2
3
4
5
6
7
8
9
10
{ "_id" : 1, "domainName" : "test1.com", "hosting" : "hostgator.com" }
{ "_id" : 2, "domainName" : "test2.com", "hosting" : "aws.amazon.com"}
{ "_id" : 3, "domainName" : "test3.com", "hosting" : "aws.amazon.com" }
{ "_id" : 4, "domainName" : "test4.com", "hosting" : "hostgator.com" }
{ "_id" : 5, "domainName" : "test5.com", "hosting" : "aws.amazon.com" }
{ "_id" : 6, "domainName" : "test6.com", "hosting" : "cloud.google.com" }
{ "_id" : 7, "domainName" : "test7.com", "hosting" : "aws.amazon.com" }
{ "_id" : 8, "domainName" : "test8.com", "hosting" : "hostgator.com" }
{ "_id" : 9, "domainName" : "test9.com", "hosting" : "cloud.google.com" }
{ "_id" : 10, "domainName" : "test10.com", "hosting" : "godaddy.com" }

导入数据:

1
mongoimport -d testdb -c website --file website.json --upsert

3.9.1 group & sort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// group by
db.website.aggregate([
{ $group: { _id: "$hosting", total: { $sum: 1 } } }
]);

// sort
db.website.aggregate([
{ $group: { _id: "$hosting", total: { $sum: 1 } } },
{ $sort: { total: -1 } }
]);

// match
db.website.aggregate([
{ $match: { hosting: "aws.amazon.com" } },
{ $group: { _id: "$hosting", total: { $sum: 1 } } },
{ $sort: { total: -1 } }
]);

3.9.2 export result

1
2
3
4
5
6
7
8
var group_data = db.website.aggregate([
{ $group: { _id: "$hosting", total: { $sum: 1 } } },
{ $sort: { total: -1 } }
]);

print(group_data.toArray())

db.websitegroup.insert(group_data.toArray())
1
2
3
mongoexport -d testdb -c websitegroup -o websitegroup.json

mongoexport -d testdb -c websitegroup -f _id,total -o websitegroup.csv --type=csv

3.9.3 Large sort operation: (sort in memory 100M)

1
2
3
4
5
6
db.website.aggregate([
{ $group: { _id: "$hosting", total: { $sum: 1 } } },
{ $sort: { total: -1 } }
],
{ allowDiskUse: true }
);

3.10 查询Embeded数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"_id": "alpha",
"name": "Storage Alpha",
"items": [
{
"category": "food",
"name": "apple"
},
{
"category": "food",
"name": "banana"
},
{
"category": "tool",
"name": "hammer"
},
{
"category": "furniture",
"name": "couch"
}
]
}

3.10.1 查询整个文档:

1
2
3
4
5
6
7
db.storage.find({
'items.category': {
$eq: 'food'
}
});

// result

3.10.2 映射操作符(Projection Operator)

1) $ 操作符会限制 array 类型数据的返回结果,使其仅返回第一个满足条件的元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
db.storage.find(
{
'items.category': {
$eq: 'food'
}
},
{
'items.$': 1
}
);

// result
{
"_id" : "alpha",
"items" : [
{
"category" : "food",
"name" : "apple"
}
]
}

2) $elemMatch$ 的区别在于,$ 使用的是数据查询条件作为来映射(或者说过滤)array 中的数据,而 $elemMatch 需要指定单独的条件(可以指定多个条件)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
db.storage.find(
{
'_id': 'alpha'
},
{
'items': {
'$elemMatch': {
'category': 'food'
}
}
}
)

// result
{
"_id" : "alpha",
"items" : [
{
"category" : "food",
"name" : "apple"
}
]
}

3.10.3 聚合

1) $filter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
db.storage.aggregate([
{
$project: {
"items": {
$filter: {
input: "$items",
as: "item",
cond: {
$eq: [ '$$item.category', 'food' ]
}
}
}
}
}
])

// result
{
"_id" : "alpha",
"items" : [
{
"category" : "food",
"name" : "apple"
},
{
"category" : "food",
"name" : "banana"
}
]
}

2) $unwind

如果文档中包含 array 类型字段、并且其中包含多个元素,使用 $unwind 操作符会根据元素数量输出多个文档,每个文档的 array 字段中仅包含 array 中的单个元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
db.storage.aggregate([
{
$match: {
'items.category': 'food'
}
},
{
$unwind: '$items'
},
{
$match: {
'items.category': 'food'
}
}
])

// result
/* 1 */
{
"_id" : "alpha",
"name" : "Storage Alpha",
"items" : {
"category" : "food",
"name" : "apple"
}
}

/* 2 */
{
"_id" : "alpha",
"name" : "Storage Alpha",
"items" : {
"category" : "food",
"name" : "banana"
}
}

4. 索引

4.1 基础索引

1
2
3
4
db.test.ensureIndex({age:1})
db.test.ensureIndex({age:1}, {background:true})

db.test.getIndexes()

4.2 文档索引

1
2
3
4
db.test.update({addr:null}, {$set: {addr: {city:'BJ', prov:'BJ'}}})
db.test.ensureIndex({addr:1})
db.test.find({addr: {city:'BJ', prov:'BJ'}}) # 使用索引
db.test.find({addr: {prov:'BJ', city:'BJ'}}) # 不使用索引

4.3 组合索引

1
db.test.ensureIndex({name:1, age:1})

4.4 唯一索引

1
db.test.ensureIndex({name:1}, {unique:true})

4.5 强制使用索引 (hint)

1
2
db.test.ensureIndex({name:1, age:1})
db.test.find({age: {$gt:25}}).hint({name:1, age:1}).explain()

4.6 删除索引

1
2
db.test.dropIndex({name:1})
db.test.dropIndexes()

5. 存储过程

5.1 定义函数

1
function addNumbers(x, y) {return x+y;}

5.2 放入js表中

1
2
db.system.js.save({_id:'addNumbers', value:addNumbers})
db.system.js.save({_id:'addNumbers', value:function(x, y) {return x+y;}})

5.3 执行存储过程

1
db.eval('addNumbers(1,2)')

6. 工具和命令

6.1 常用命令

1
2
3
4
5
6
7
8
9
bsondump	bson格式文件转换为json
mongo 客户端, js解释器
mongod 服务器,每个实例启动一个进程
mongodump/mongorestore
mongoexport/mongoimport
mongofile GridFS管理器,实现二进制文件存取
mongos 分片路由,使用sharding功能时,应用程序连接mongos,而不是mongod
mongosniff tcpdump,监控mongodb相关包请求,并已指定可读形式输出
mongostat 实时监控工具

6.2 数据导出

1
2
3
4
5
6
7
mongoexport
-d, --db
-c, --collection
-o, --out
-f, --fields
--host/--port
-csv, --type=csv
1
2
mongoexport -d mydb -c test -o test.json
mongoexport -d mydb -c test -f name,addr --type=csv -o test.csv

6.3 数据导入

1
2
3
4
5
6
7
8
9
10
mongoimport
-d, --db
-c, --collection
-f, --fields
--host/--port
-csv, --type=csv
--drop => drop collecion first if exists
--stopOnError
--file
--headerline # 忽略第一行
1
mongoimport -d mydb -c test --headerline --type=csv --drop --file test.csv

6.4 数据库备份恢复

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1) mongodump
-d, --db
-c, --collection
-o, --out
-q, --query

mongodump -d mydb # 生成dump目录,该目录下保存数据文件

2) mongorestore
-d, --db
-c, --collection
--objcheck
--filter
--drop

 上一页