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'})
|
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() db.test.findOne(). db.test.find({name:'jack'}) db.test.find({name:'jack', age:29})
db.test.find({}, {name:1, gender:1}) db.test.find({}, {email:0})
|
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.*/}})
|
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']}})
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
| db.website.aggregate([ { $group: { _id: "$hosting", total: { $sum: 1 } } } ]);
db.website.aggregate([ { $group: { _id: "$hosting", total: { $sum: 1 } } }, { $sort: { total: -1 } } ]);
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' } });
|
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 } );
{ "_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' } } } )
{ "_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' ] } } } } } ])
{ "_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' } } ])
{ "_id" : "alpha", "name" : "Storage Alpha", "items" : { "category" : "food", "name" : "apple" } }
{ "_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
|