在MongoDB中,要操作一个表并不需要先创建它,可以直接往集合中插入数据,如果集合不存在,会自动创建这个集合。
db.testcollection.insert({"database":"no_sql"}) //集合相当于一张表;
Config:当MONGO用于分片设置时,config数据库在内部使用,用于保存分片的相关信息。
体系结构:
Admin:从权限角度来看,这是ROOT数据库,在ADMIN数据库中添加的用户会自动继承所有数据库权限,一些特定的服务器端命令也只能从这个数据库运行,如列出所有的数据库,关闭服务器。
Local:该数据库永远不会被复制,可以用来存储限于本地单台服务器的任意集合;
Config:当MongoDB用于分片设置时,config数据库在内部使用。用于保存分片的相关信息;
每个数据库文件最大2GB,
文档中的KEY类似于数据库中的字段,下划线_开头的键是保留的,$和.有特殊意义。不能有空格;键可以是任意UTF8字符;
同一个文档中,键是不能重复的。集合不能以system命名;system.namespaces这个集合保存着所有数据集合的信息;
db.createCollection("persion") #创建一个集合;默认为use test ; db;
GridFS大文件协议;JSON:只有null,bool,数字,字符串,数组和对象;
32位整数在shell中不可用,因为js仅支持64位浮点。所有32位整数会被自动转换;
64位整数:
-----------------------------------------data types-----------
null{"X":null} bool{"x":true}
32位整数 64位整数 64位浮点{"X":12}shell中的浮点都是这种类型 [mongo的三种数字类型]
字符串 符号 对象ID{"X":ObjectId()} 对象id是文档的12字节的唯一ID
日期{"X":new Date()}
正则{"X":/persioninfo/i}
代码{"x":function(){...}}
二进制数据;
其它类型:最大值,最小值,未定义{"x":undefined}
数组{"x":["a","b","c"]},内嵌文档:{"x":{"name":"zhangshan"}}
--------------------------------------------------------------
typeof Date() //string
typeof new Date() //object 注意统一:要么对象,要么字串,不然更新,查找不统一的时间,处理起来相就不便了。
ObjectId是“_id"的默认类型,MongoDb采用ObjectId,12字节,24位字串。(时间戳,机器码,PID,计数)(pid为进程标识)。
---------------------------------------------------------------
post.comment=[] //增加一个评论属性;空数组;
mongo shell:
personbaseinfo={“name":"tom","age":18}
db.persion.insert(personbaseinfo)
person.age = 20 //改上一个
db.persion.findOne()
db.person.update({"name":"tom"},personbaseinfo) //前一个为查询条件,后一个为更新的变量;
db.person.remove({"name":"tom"}) //删除,根据一个条件;
进行插入更新操作前,先把数据保存在变量中好些:
person = {"name":"zhanogshangfeng","age":8};
db.person.insert(person);
db.
MongoDB在执行插入时,首先会将插入的数据转换成BSON格式,然后MongoDb数据库会对BSON进行解析,并检查是否存在_id键。单文档不能超过16M。查看文档的大小,用 Object.bsonsize(doc)查看;
mongoimport:数据导入工具;
组织集合的一种贯例是使用 . 分隔不同命令空间的子集合,blog.posts.为了使组织结构更清晰;
-----------------------------------------------
find自动显示20个文档;
db.personlinfo.find()//先查询;
p = {"name":"zhangshang","age":8}
db.personinfo.insert(p);
插入原理:先转BSON,对BSON进行解析,并检查是否存在_id键。
启动时加 --objcheck 在插入之前先检查文档的有效性;
删除: db.p.remove() , db.p.drop() //第二个连索引都删了;
person.findOne()和FIND,一个是临时赋值,一个是可以永久使用;
更新: 1.先 var p = db.person.findOne();
而后更改: p.*,p.username =
delete p.name =
然后改完变量后,更新:
3.db.person.update({"name":"tom"},p) //更新条件为name=tom
改变整个结果:更新的方法:1.先findOne(),赋值,而后.***属性赋值;而后再delete *.per*删除多余的不要的,最后.update({条件},{刚才的}),从而完成更新;
修改器: {"$inc":{"age":1}}
{"$set":{"address":"816 park street"}} $set修改器用来修改指定一个键的值;如果键值不存在,则自动创建它;甚至可以修改数据类型;
用$set修改器设置内嵌文档: {"$set":{"address.street":"822 street.}}//修改address内嵌文档
注意这里的区别:address.street 中间有点;
"age":9,“address":{"city":"beijing","street":"8267 park street"}
$inc修改器只用于整数,长整或双精度浮点数。
数组修改器:数组操作只能在值为数组的键上。$push操作指定的键,如果键(键的值为数组)存在,会在己有的数组末尾加入一个元素,如果键不存在就会创建一个新的数组;
{$push:{"favbook":"MongoDB"}}
"favbook":["mongoDB"]} //#如果键存在,则加,["Mongdo","hBase"]
还可以使用$ne来判断一个值是否在数组中,如果不在,则添加;
.update({"favbook":{"$ne":"adv math"}},{$push:{"favbook":"adv Math"}})
{"$addToSet":{"email":"xxx"}} //存在就不加,不存在则添加进去;
一次添加多个邮箱信息:
db.personinfo.update(,{"$addToSet":{"emails":{"$each":{"@163.com","@yahoo.com","qq@.com"}}}})
{"$pop":{"emails":1}}出栈,尾删
{"$pop":{"emails":-1}}开头删。
{"$pull":{"emails":"xhang@163.com"}} //删除163.com的邮箱;
数组的下标表示: {"emails.0":"xxx"} //用于set...等数组操作;
$定位器:{"$set":{"address.$.street":"571 park street"}} 用来替代address.1.street定位的
update()的第三个参数upsert为真,有更新,没有则创建;代表是否查询不到的创建;
save()是一个shell函数,可以在文档不存在时插入,存在时更新,save()函数只有一个参数,参数为文档。
第四个参数:修改多个文档;修改的结果为多行,一定要把第四个多行打开;想要知道影响的记录条目数,调用 db.runCommand({getLastError:1}) n表示条数;
find不带参数查询所有的文档,第一个参数指定了要返回哪些文档;就是所谓的查询条件;
db.person.find({"age":20}),第二个字段指定字段
db.person.find({},{"age":1})
db.personinfo.update({"favbook":{"$ne":"Math"}},{$push:{"favbook":"Math"}}) //第一个为查询条件,第二为没有则加,$addToSet完成同样的功能,没有则追加;
.limit().sort({})
ps = db.runCommand({"findAndModify...
db.person.find({"age":{"$gt":20}}) 查询年龄大于20的
in只需要满足()内的某一个值即可,$all必须满足[]内的所有值;
{"$all":["tiger","horse"]}
db.animal.find({"animal":["tiger","lion","horse","elephant"]})
由于mongodb反范式,则可以通过$exists查是否存在某字段;
db.person.find({"age":{"$exists":true}})
db.person.find({"age":{"$in":k[null],"$exists":true}) //查询age为null的文档;
{"$mod":[8,1]} //取余8余1的,比如9,,则为真
$ne不等于:{"age":{"$ne":9}}
$in 包含 {"age":{"$in":[8,9]}}
$nin 不包含 {"age":{"$nin":[8,9]}}
$size 数组长度{{"age":{"$size":3}}}
.find({"name":/s/}) //查询名字中带S的正则查询;
db.person.find({"$where":"this.age>20"})
定义一个函数:
f = function () { return this.age > 20}
而后
db.person.find(f)
{"$where":"this.x+this.y==9"})
this.代指当前文档对象;
count查询记录条数;
db.person.find.count()
db.person.find().skip(2).limit(5).count(true) //显示实际的记录数;
find().sort({"age":1,"age":-1})
使用skip()略过少量的文档速度可以,但如果过多,就会慢;
db.runCommand({"distinct":"person","key":"age"}) 去重;
group()分组
定义函数: $keyf
var cursor = db.test.find() //获取游标
while(cursor.hasNext()){
... printjson(cursor.next())
... }
forEach接口:
cursor.forEach(function(obj){
print(obj.x)
})
存储过程:db.system.js
db.system.js.save({"_id":"addNum",
value:function(x,y){
reuturn x+y
}})
调用存储过程:db.eval('addNum(6,52)')
db.eval(function(){return 6+2;
db.createCollection("mywebLog",{"capped":true,"size":1000000,”max“:100,"autoIndexId":true}) //创建固定集合,限制集合的个数;
db.mywebLog.validate()
每种编程语言表示文档的方法不一样:JS中,文档被表示为对象:
{"greeting":"hello,world!"}
gteeting称为键;包含键/值对;
子集合:使用子集合来组织数据非常高效。
db 查看当前使用的数据库; use db
在JS中,Date日期应使用new Date()
mongo --nodb 启动时不连接DB数据库
------------------------------------
conn = new Mongo("some-host:30000")
db = conn.getDB('myweb')
在shell中连接
------------------------------------
在shell中执行脚本:
mongo script.js script2.js
后再跟上脚本名称: mongo --quiet server-1:3000/foo script.js
script2.js script.js
load("script.js") //在交互环境中加载.js
-----------------------------------------
use foo ==== db.getSisterDB('blog')
show dbs ======= db.getMongo()
show collections db.getCollectionNames()
------------------------------------------
typeof 函数
------------------------------------------
db.getCollection('version');
------------------------------------------
var x = {y:2}
x.y //2
x['y'] //2 语法上相等;
------------------------------------------
db.foo.batchInsert([{},{}]) //批量插入,接受一个文档数组参数
------------------------------------------
new Date().getTime() //产生一个时间戳;13位 1520411478760
替换文档: 先findOne()给变量,然后p.属性={}文档;
然后 delete p.属性
相当于修改好变量的值,然后 update({条件},p); //一次更新;
原子性的修改器:更新器是种特殊的键,用来指定复杂的更新操作;
$Set 用来指定一个字段的值,如果不存在,则创建;也可以改变类型,也可
以用$unset删除;
$push 向己有数组末尾加入一个元素;没有就创建新;
db.blog.posts.update({"title":"a blog",{"$push":{"comments":
{"name":"joe","...}
$pop {"key"-1}
$pull 按特定条件删
db.raffle.find({"$or":[{"ticket_no"725},{"winner":true}]})//
{"$or":[{},{}]}//or后面接数组;
{"$mod":[5,2]}
{"$not":}
"$in":[4,5]}
"$exists":true
.find({"name":/joe/i})
{$all:["apple","banna"]}
db.food.find({"fruit.2":"peach"})
findOne(criteria,{"comments":{"$slice":10}}) //返回10条评论;
$elemMatch 不会匹配非数组元素;{"$elemMatch":10,"$lt":20}
while(cursor.hasNext()){
obj = cursor.next();
}
var cursor = db.blog.find();
cursor.forEach(function(x){
print(x.name);
});
db.blog.find()._addSpecial("$maxscan",20)
在多个键上建立的索引就是复合索引。只有在基于多键排序时,方向才变得
重要;
覆盖索引:当一个索引包含用户请求的所有字段,可以认为这个索引覆盖了
本次查询。
如果在覆盖索引上执行explain(),"indexOnly"字段的值要为true;
db.entries.find({"created_at":{"$lt":hourAge}}).hint({$natural":1})
用{"$natural":1}强制做数据库全表扫描。它可以指定文档按照磁盘上的顺
序排列。
如果要得到最新的(最早的)文档,这个就很好用。
唯一性索引: db.users.ensureIndex({"username":1},{"unique":true});
己有文档去重:db.users.ensureIndex({"age":1},{"unique":true})//
sparse index 稀疏索引{"unique":true,"sparse":true}
hint()强制进行全表扫描;
所有的数据库索引信息存在system.indexes集合中。这是保留集合,不能插
入或删除,只能通过ensureIndex或dropIndexes对其操作;
db.person.getIndexes() 查看给定集合上的所有索引信息;
固定集合不能被分片
db.runCommand({"convertToCapped":"test","size":10000})//普通集合转
成固定集合;
自然排序:
db.person.find().sort({"$natural":1});
没有_id索引的集合,创建集合时指定autoIndexId选项为false,创建集合时
就不会自动在_id上创建索引。
db.runCommand({text:"hn",search:"\"ask hn \" ipod})
db.blog.ensureIndex({"date":1,"post":"text"})
mongofiles put foo.txt //存储
mongofiles get foo.txt // 取出
list,search,delete 一共5种操作;
--------------------------------------
PyMongo
from pymongo import Connection
import gridfs
db = Connection().test
fs = gridfs.GridFS(db)
file_id = fs.put("hello world", filename = "foo.txt")
fs.list()
fs.get(file_id).read()
-----------------------------------------
db.fs.files.distinct("filename")
$matc用于对文档集合进行筛选,之后就可以在筛选得到的文档子集上做聚合
。
db.runCommand({"distinct":"people","key":"age"})
客户端不能在备份节点执行写操作,默认情况下,客户端不能从备份节点中
读取数据,在备份节点上显示地执行setSlaveOk之后,客户端就可以从备份
节点中读取数据了。
mongod --replSet spock -f mongod.conf --fork // --replSet 后跟
name ;
mongoDB中,每个集合最多可以创建64个索引,它支持能在RDBMS中找到各种
索引,升,降,唯一,复合键索引,地理空音索引被支持,mongodB的二级索
引用B树b-tree实现。
副本集:如果一个读密集型的应用,可以把数据库读操作分散到副本集集群
的各台机器上。
副本集的从节点是只读的;副本集支持自动故障转移。
对于高容量,低价值的数据,fire-and-forget风格的写操作是很理想的选择
。
提升单一的硬件来进行扩展称为垂直扩展或向上扩展。、
水平扩展是将数据库分布到多台机器上。
mongod服务器进程使用一个自定义二进制协议从网络套接字上接收命令。
mongodump,mongorestore 备份和恢复;
mongoexport,mongoimport导入导出json,csv,tsv数据
mongosniff 观察发送到数据库的操作;把网络上传输的bson转换为易于人们
阅读的shell语句。
mongostat 持续轮询mongodb和系统以便提供有帮助的统计信息。
bsondump,mongofiles;
$push,$addToSet这两个操作都是向数组添加一个元素,但后者会保证唯一性
,防重复。
db.numbers.ensureindex({name:1}); //创建索引
db.numbers.getIndexes() //查看索引
db.stats()
db.runCommand({dbstats:1})
db.runCommand({collstats:'numbers'})
db.products.ensureIndex({sulg:1},{unique:true})
查询指定产品的分类:
db.categories.find({_id:{$in:product['category_ids']}});
db.blog.find({num:{$in:[2,3,5]}})
文件大小上限,2GB。
插入文件就创建了集合,但是有各种各样的集合,可能执行
db.createCollection("users")创建集合。db.createCollection("users",
{sze:20000})
db.products.renameCollection("store_products") //重命名集合;
db.user.actions.find().sort({"$natural":-1});
bson规定了三种数字类型,double,int,long,也就是说bson可以编码各种
ieee浮点数值,以及各种8字节以内的带符号的整数;js天生支持一种Number
,等于ieee的双精浮点;如果要在shell中将一个数字保存为整数,需要使用
NumberLong(),NumberInt();
db.number.save({n:5});
db.number.save({n:NumberLong(5)});
db.number.find({n:{$type:1}}) //根据类型来查
db.number.find({n:{$type:18}) //
mongodb.v2.0的bson文档限制大小16M。
find()返回的是游标对象,而findOne()返回的是一个文档。仅仅要一个文档
,就用findOne(),如果需要返回多个文档,就需要使用find(),该方法会返回
一个游标,你需要进行迭代。
db.users.find({last_name:/^Ba/}) //查询以Ba开头的名字
db.orders.find({'line_items.sku':1,'purcharse_date':{$gte:new Date
(2009,0,1)}})
.toArray().map(function(doc){ return doc['user_id']})
.toArray() //返回数组; [{},{}]
------------------------------------------------------------------
db.blog.find({num:{$lt:4}}).map(function(doc){ return doc['num']})
[ 0, 1, 2, 3 ] //doc就是当前的文档.然后输出'num字段
------------------------------------------------------------------
{$in:[x,x,x,x]},{$nin:['balck','blue']}
{$in:[x,x,x,x]},{$all:['balck','blue']}
{$or:['balck','blue']}
{$ne:'greeting'}
布尔操作:ne,not,and,exists
db.user.find(last_name:{$not:/^B})
db.user.find({address:{$eleMatch:{name:'home',state:'NY'}})
要将多个条件限制在同一个子文档上,可以用$elemMatch操作符;需要匹配
子文档的多个属性才用。
db.user.find({addresses:{$size:3}})
db.blog.find({$where:"function(){ return this.num<4;}"}) //$where
函数;
db.reviews.find({user_id:ObjectId("****"),text:/best|worst/i}) //查
指定用户评论中含best,worst单词的。
db.user.find({_id:{$type:2}}) //找出id类型为字符串的文档;
投影:约束结果集;
db.products.find({},{reviews:{$slice:12}}) //返回头12篇评论
db.products.find({},{reviews:{$slice:-5}}) //返回倒数第5篇
db.products.find({},{reviews:{$slice:[24,12]}}) //跳过24,返回12
篇
db.products.find({},{reviews:{$slice:[24,12]}},'_id':1)//显示12篇
评论及id;
group最少需要三个参数:第一个key,定义如何对数据进行分组,第二个参数
是对结果做聚合的js函数,叫reduce函数,第三个分组参数是reduce函数的
初始文档;
results = db.reviews.group({
key:{user_id:true},
initial:{reviews:0,votes:0.0},
reduce:function(doc,aggregator){
aggregator.reviews+=1;
aggregator.votes +=doc.votes;
}
finalize:function(doc){
doc.average = doc.votes/doc.reviews;
}
})
finalizer终结器:在group命令返回前应用于每个分组结果上。
map = function(){
var shipping_month = this.purchase_date.getMonth
()+'-'+this.purchase_data.getFullYear();
var items = 0;
this.line_items.forEach(function(item){
items+=item.quantity;
});
emit(shipping_month,
{order_total:this.sub_total,items_total:items});
//说明:this总是指向正在迭代的文档,随后调用emit(),这是每个映射函
数必须要调用的特殊方法,emit()第一个参数是分组依据的键,第二个通常
是包含要执行reduce的值的文档。
reduce ,用于执行聚合的JS函数,该函数接受两个参数,正被迭代的当前文
档和用于存储聚合结果的聚合器文档。reduce函数不返回任何内容,只不过
修改聚合器对象。
finalize:在返回结果集之前应用每个结果文档的JS函数,该函数支持对分组
操作的结果进行后置处理。
比较时间: filter = {purchase_date :{$gte: new Date(2010,1,1)}}
db.blog.distinct("tags") //去重
db.blog.distinct("tags",category_id:12) //去重,显示分类去重;
group,distinct数据库命令,结果集受16M数据库大小的影响。
group不会处理多于1万个唯一键;
-------------------------------------------------
db.collection.mapReduce(
function() {emit(key,value);}, //map 函数
function(key,values) {return reduceFunction}, //reduce 函数
{
out: collection,
query: document,
sort: document,
limit: number
}
)
-------------------------------
map :映射函数 (生成键值对序列,作为 reduce 函数参数)。
reduce 统计函数,reduce函数的任务就是将key-values变成key-value
,也就是把values数组变成一个单一的值value。。
out 统计结果存放集合 (不指定则使用临时集合,在客户端断开后自动删
除)。
query 一个筛选条件,只有满足条件的文档才会调用map函数。(query
。limit,sort可以随意组合)
sort 和limit结合的sort排序参数(也是在发往map函数前给文档排序)
,可以优化分组机制
limit 发往map函数的文档数量的上限(要是没有limit,单独使用sort
的用处不大)
-------------------------------
每种编程语言表示文档的方法不一样:JS中,文档被表示为对象: {"greeting":"hello,world!"}
gteeting称为键;包含键/值对;
子集合:使用子集合来组织数据非常高效。
db 查看当前使用的数据库; use db
在JS中,Date日期应使用new Date()
mongo --nodb 启动时不连接DB数据库
------------------------------------
conn = new Mongo("some-host:30000")
db = conn.getDB('myweb')
在shell中连接
------------------------------------
在shell中执行脚本:
mongo script.js script2.js
load("script.js") //在交互环境中加载.js
-----------------------------------------
use foo ==== db.getSisterDB('blog')
show dbs ======= db.getMongo()
show collections db.getCollectionNames()
------------------------------------------
typeof 函数
------------------------------------------
db.getCollection('version');
------------------------------------------
var x = {y:2}
x.y //2
x['y'] //2 语法上相等;
------------------------------------------
db.foo.batchInsert([{},{}]) //批量插入,接受一个文档数组参数
------------------------------------------
new Date().getTime() //产生一个时间戳;13位 1520411478760
替换文档: 先findOne()给变量,然后p.属性={}文档;
然后 delete p.属性
相当于修改好变量的值,然后 update({条件},p); //一次更新;
原子性的修改器:更新器是种特殊的键,用来指定复杂的更新操作;
$Set 用来指定一个字段的值,如果不存在,则创建;也可以改变类型,也可以用$unset删除;
$push 向己有数组末尾加入一个元素;没有就创建新;
db.blog.posts.update({"title":"a blog",{"$push":{"comments":{"name":"joe","...}
$pop {"key"-1}
$pull 按特定条件删
db.raffle.find({"$or":[{"ticket_no"725},{"winner":true}]})//{"$or":[{},{}]}//or后面接数组;
{"$mod":[5,2]}
{"$not":}
"$in":[4,5]}
"$exists":true
.find({"name":/joe/i})
{$all:["apple","banna"]}
db.food.find({"fruit.2":"peach"})
findOne(criteria,{"comments":{"$slice":10}}) //返回10条评论;
$elemMatch 不会匹配非数组元素;{"$elemMatch":10,"$lt":20}
while(cursor.hasNext()){
obj = cursor.next();
}
var cursor = db.blog.find();
cursor.forEach(function(x){
print(x.name);
});
db.blog.find()._addSpecial("$maxscan",20)
在多个键上建立的索引就是复合索引。只有在基于多键排序时,方向才变得重要;
覆盖索引:当一个索引包含用户请求的所有字段,可以认为这个索引覆盖了本次查询。
如果在覆盖索引上执行explain(),"indexOnly"字段的值要为true;
db.entries.find({"created_at":{"$lt":hourAge}}).hint({$natural":1})
用{"$natural":1}强制做数据库全表扫描。它可以指定文档按照磁盘上的顺序排列。
如果要得到最新的(最早的)文档,这个就很好用。
唯一性索引: db.users.ensureIndex({"username":1},{"unique":true});
己有文档去重:db.users.ensureIndex({"age":1},{"unique":true})//
sparse index 稀疏索引{"unique":true,"sparse":true}
hint()强制进行全表扫描;
所有的数据库索引信息存在system.indexes集合中。这是保留集合,不能插入或删除,只能通过ensureIndex或dropIndexes对其操作;
db.person.getIndexes() 查看给定集合上的所有索引信息;
固定集合不能被分片
db.runCommand({"convertToCapped":"test","size":10000})//普通集合转成固定集合;
自然排序:
db.person.find().sort({"$natural":1});
没有_id索引的集合,创建集合时指定autoIndexId选项为false,创建集合时就不会自动在_id上创建索引。
db.runCommand({text:"hn",search:"\"ask hn \" ipod})
db.blog.ensureIndex({"date":1,"post":"text"})
mongofiles put foo.txt //存储
mongofiles get foo.txt // 取出
list,search,delete 一共5种操作;
--------------------------------------
PyMongo
from pymongo import Connection
import gridfs
db = Connection().test
fs = gridfs.GridFS(db)
file_id = fs.put("hello world", filename = "foo.txt")
fs.list()
fs.get(file_id).read()
-----------------------------------------
db.fs.files.distinct("filename")
$matc用于对文档集合进行筛选,之后就可以在筛选得到的文档子集上做聚合。
db.runCommand({"distinct":"people","key":"age"})
客户端不能在备份节点执行写操作,默认情况下,客户端不能从备份节点中读取数据,在备份节点上显示地执行setSlaveOk之后,客户端就可以从备份节点中读取数据了。
mongod --replSet spock -f mongod.conf --fork // --replSet 后跟name ;
mongoDB中,每个集合最多可以创建64个索引,它支持能在RDBMS中找到各种索引,升,降,唯一,复合键索引,地理空音索引被支持,mongodB的二级索引用B树b-tree实现。
副本集:如果一个读密集型的应用,可以把数据库读操作分散到副本集集群的各台机器上。
副本集的从节点是只读的;副本集支持自动故障转移。
对于高容量,低价值的数据,fire-and-forget风格的写操作是很理想的选择。
提升单一的硬件来进行扩展称为垂直扩展或向上扩展。、
水平扩展是将数据库分布到多台机器上。
mongod服务器进程使用一个自定义二进制协议从网络套接字上接收命令。
mongodump,mongorestore 备份和恢复;
mongoexport,mongoimport导入导出json,csv,tsv数据
mongosniff 观察发送到数据库的操作;把网络上传输的bson转换为易于人们阅读的shell语句。
mongostat 持续轮询mongodb和系统以便提供有帮助的统计信息。
bsondump,mongofiles;
$push,$addToSet这两个操作都是向数组添加一个元素,但后者会保证唯一性,防重复。
db.numbers.ensureindex({name:1}); //创建索引
db.numbers.getIndexes() //查看索引
db.stats()
db.runCommand({dbstats:1})
db.runCommand({collstats:'numbers'})
db.products.ensureIndex({sulg:1},{unique:true})
查询指定产品的分类:
db.categories.find({_id:{$in:product['category_ids']}});
db.blog.find({num:{$in:[2,3,5]}})
文件大小上限,2GB。
插入文件就创建了集合,但是有各种各样的集合,可能执行db.createCollection("users")创建集合。db.createCollection("users",{sze:20000})
db.products.renameCollection("store_products") //重命名集合;
db.user.actions.find().sort({"$natural":-1});
bson规定了三种数字类型,double,int,long,也就是说bson可以编码各种ieee浮点数值,以及各种8字节以内的带符号的整数;js天生支持一种Number ,等于ieee的双精浮点;如果要在shell中将一个数字保存为整数,需要使用NumberLong(),NumberInt();
db.number.save({n:5});
db.number.save({n:NumberLong(5)});
db.number.find({n:{$type:1}}) //根据类型来查
db.number.find({n:{$type:18}) //
mongodb.v2.0的bson文档限制大小16M。
find()返回的是游标对象,而findOne()返回的是一个文档。仅仅要一个文档,就用findOne(),如果需要返回多个文档,就需要使用find(),该方法会返回一个游标,你需要进行迭代。
db.users.find({last_name:/^Ba/}) //查询以Ba开头的名字
db.orders.find({'line_items.sku':1,'purcharse_date':{$gte:new Date(2009,0,1)}})
.toArray().map(function(doc){ return doc['user_id']})
.toArray() //返回数组; [{},{}]
------------------------------------------------------------------
db.blog.find({num:{$lt:4}}).map(function(doc){ return doc['num']})
[ 0, 1, 2, 3 ] //doc就是当前的文档.然后输出'num字段
------------------------------------------------------------------
{$in:[x,x,x,x]},{$nin:['balck','blue']}
{$in:[x,x,x,x]},{$all:['balck','blue']}
{$or:['balck','blue']}
{$ne:'greeting'}
布尔操作:ne,not,and,exists
db.user.find(last_name:{$not:/^B})
db.user.find({address:{$eleMatch:{name:'home',state:'NY'}})
要将多个条件限制在同一个子文档上,可以用$elemMatch操作符;需要匹配子文档的多个属性才用。
db.user.find({addresses:{$size:3}})
db.blog.find({$where:"function(){ return this.num<4;}"}) //$where函数;
db.reviews.find({user_id:ObjectId("****"),text:/best|worst/i}) //查指定用户评论中含best,worst单词的。
db.user.find({_id:{$type:2}}) //找出id类型为字符串的文档;
投影:约束结果集;
db.products.find({},{reviews:{$slice:12}}) //返回头12篇评论
db.products.find({},{reviews:{$slice:-5}}) //返回倒数第5篇
db.products.find({},{reviews:{$slice:[24,12]}}) //跳过24,返回12篇
db.products.find({},{reviews:{$slice:[24,12]}},'_id':1)//显示12篇评论及id;
group最少需要三个参数:第一个key,定义如何对数据进行分组,第二个参数是对结果做聚合的js函数,叫reduce函数,第三个分组参数是reduce函数的初始文档;
results = db.reviews.group({
key:{user_id:true},
initial:{reviews:0,votes:0.0},
reduce:function(doc,aggregator){
aggregator.reviews+=1;
aggregator.votes +=doc.votes;
}
finalize:function(doc){
doc.average = doc.votes/doc.reviews;
}
})
finalizer终结器:在group命令返回前应用于每个分组结果上。
map = function(){
var shipping_month = this.purchase_date.getMonth()+'-'+this.purchase_data.getFullYear();
var items = 0;
this.line_items.forEach(function(item){
items+=item.quantity;
});
emit(shipping_month,{order_total:this.sub_total,items_total:items});
//说明:this总是指向正在迭代的文档,随后调用emit(),这是每个映射函数必须要调用的特殊方法,emit()第一个参数是分组依据的键,第二个通常是包含要执行reduce的值的文档。
reduce ,用于执行聚合的JS函数,该函数接受两个参数,正被迭代的当前文档和用于存储聚合结果的聚合器文档。reduce函数不返回任何内容,只不过修改聚合器对象。
finalize:在返回结果集之前应用每个结果文档的JS函数,该函数支持对分组操作的结果进行后置处理。
比较时间: filter = {purchase_date :{$gte: new Date(2010,1,1)}}
db.blog.distinct("tags") //去重
db.blog.distinct("tags",category_id:12) //去重,显示分类去重;
group,distinct数据库命令,结果集受16M数据库大小的影响。
group不会处理多于1万个唯一键;
-------------------------------------------------
db.collection.mapReduce(
function() {emit(key,value);}, //map 函数
function(key,values) {return reduceFunction}, //reduce 函数
{
out: collection,
query: document,
sort: document,
limit: number
}
)
-------------------------------
map :映射函数 (生成键值对序列,作为 reduce 函数参数)。
reduce 统计函数,reduce函数的任务就是将key-values变成key-value,也就是把values数组变成一个单一的值value。。
out 统计结果存放集合 (不指定则使用临时集合,在客户端断开后自动删除)。
query 一个筛选条件,只有满足条件的文档才会调用map函数。(query。limit,sort可以随意组合)
sort 和limit结合的sort排序参数(也是在发往map函数前给文档排序),可以优化分组机制
limit 发往map函数的文档数量的上限(要是没有limit,单独使用sort的用处不大)
-------------------------------
如果有a-b的复合索引,那么仅针对a的索引就是冗余的。复合索引里键的顺序很重要。
后台索引:虽然索引构建仍会占用写锁,但构建任务会停下来允许其他读写操作访问数据库。db.values.ensureIndex({open:1,close:1},{background:true}});
db.values.reIndex(); //重建指定集合上的所有索引;
开启服务器慢查询剖析器:
use stocks;
db.setProfilingLevel(2)
db.setProfilingLevel(1,50)//禁用将第一个参数设为0,第二个参数为毫秒
db.value.getIndexKeys() //列出索引
用explain(true)查看查询计划
复制:二种:1.主从;2.副本集;
最小的副本集由三个节点组成,二个一等节点,外加一个仲裁节点。
---------------------------
创建副本集:
三台机器只是dbpath不同。端口不同;
D:\MongoDB\Server\3.6\bin>mongod --replSet myapp --dbpath c:\data\node1 --port 40000
D:\MongoDB\Server\3.6\bin>mongod --replSet myapp --dbpath c:\data\node1 --port 40001
D:\MongoDB\Server\3.6\bin>mongod --replSet myapp --dbpath c:\data\node1 --port 40002
连接到非仲裁节点后运行:
1.rs.initiate()
2.rs.add("localhost:40001")
3.rs.add("localhost:40002",{arbiterOnly:true});
db.isMaster()
rs.status()
rs.remove("localhost:4000")
--------------------------------
cfg = rs.conf()
cfg.members[0].host = "你的IP 或者域名"
rs.reconfig(cfg)
--------------------------------
查看日志:
use local
db.oplog.rs.find();
local数据库里保存了所有的副本集元数据和oplog。当然,这个数据库本身不能被复制,正如其名,local数据库里的数据对本地节点而言是唯一的,因此不该复制;
-------------------------
用脚本配置:
config = {_id:"myapp",members:[]}
config.members.push({_id:0,host:'localhost:4000'})
config.members.push({_id:1,host:'localhost:4001'})
config.members.push({_id:2,host:'localhost:4002',arbiterOnly:true})
rs.initiate(config)
-------------------------
db.runCommand({replSetInitiate:config});
rs.slaveOk() //允许副本查询
-------------------------
rs.help() //查看所有的副本集命令;
配置文档选项:
_id,host,arbiterOnly,priority(0-1000),votes,hidden(bool,在isMaster命令生成的响应中不会出现该结点,因为mongodB驱动依赖于isMaster来获取副本集的拓扑情况,隐藏一个成员能避免驱动自动访问它。buildIndexes(bool),slaveDelay()指定从节点迟延的秒数;
tags,getLastErrorDefaults,getLastErrorModes.
配置文件:use local; db.system.replset.find()
配置:
-----------------------------------------
use local;
config = db.system.replset.findOne();
config.members[1].host = "localhost:4000";
rs.reconfig(config)
------
rs.reconfig(config,{force:true}})//强制重新加载配置
-----------------------------------------
连接到从结点的时候,加connection(host,slave_ok=>true)避免无意向从节点进行写操作;
写关注:insert(doc,{w:2,wtimeout:500}) //2台服务器,500毫秒
2.0最多支持12个成员副本集,如果还想更多,则需要分片集群;
数据集标签:每个成员标签文档有两个键值对,第一个标识了数据中心,第二个是指定节点服务器所在机器的名称。
分片集群由分片,mongos路由器和配置服务器组成:
配置服务器:全局集群配置,每个数据库、集合和特定范围数据的位置,一份变更记录,保存了数据在分片之间进行迁移的历史信息。
mongos进程向配置服务器写入时,会使用两阶段提交,这能保证配置服务器之间的一致性,在各种生产环境的分片部署中,必须运行三个配置服务器。
分片是基于范围的,分片集合里的每个文档都必须落在指定键的某个值范围里,mongodb使用的所谓的分片键,让每个文档在这些范围里找到自己的位置。
分片配置:
--configsvr
--shardsvr
-----------------------------------------脚本
mongod --shardsvr --replSet shard-a --dbpath c:\data\rs-a-1 --port 3000 --logpath c:\data\rs-a-1.log --fork --nojournal
mongod --shardsvr --replSet shard-a --dbpath c:\data\rs-a-2 --port 3001 --logpath c:\data\rs-a-2.log --fork --nojournal
mongod --shardsvr --replSet shard-a --dbpath c:\data\rs-a-3 --port 3002 --logpath c:\data\rs-a-3.log --fork --nojournal
mongod --shardsvr --replSet shard-b --dbpath c:\data\rs-b-1 --port 4000 --logpath c:\data\rs-b-1.log --fork --nojournal
mongod --shardsvr --replSet shard-b --dbpath c:\data\rs-b-2 --port 4001 --logpath c:\data\rs-b-2.log
mongod --shardsvr --replSet shard-b --dbpath c:\data\rs-b-3 --port 4002 --logpath c:\data\rs-b-3.log --fork --nojournal
mongod --configsvr --replSet conf --dbpath c:\data\config-1 --port 27019 --logpath c:\data\config-1.log
mongod --configsvr --replSet conf --dbpath c:\data\config-2 --port 27020 --logpath c:\data\config-2.log
mongod --configsvr --replSet conf --dbpath c:\data\config-3 --port 27021 --logpath c:\data\config-3.log
然后初始化三台配置服务器:
rs.initiate()
rs.add("123") //注意要把3台都加成配置服务器,配置服务器没有仲裁;
配置完成后,查看状态,成功后,才能用 mongos命令;
mongos --configdb conf/localhost:27019,localhost:27020,localhost:27021 --logpath c:\data\mongos.log --port 5000
高版本的变化,即配置服务器也要指定副本集,然后mongos要指定conf/localhost:27019 配置集:conf:/localhost:27019,localhost:27029...
然后连接mongos的端口,成功后,可见mongs> 提示符;
sh.addShard("shard-a/localhost:3000,localhost:3001")
sh.addShard("shard-b/localhost:4000,localhost:4001")
然后将二个副本集加入分片,注意不要加仲裁节点。后功后即可看到状态;
rs.status()
-------------------------------
mongos> sh.status()
--- Sharding Status ---
sharding version: {
"_id" : 1,
"minCompatibleVersion" : 5,
"currentVersion" : 6,
"clusterId" : ObjectId("5aa632424911a3657d360c7f")
}
shards:
{ "_id" : "shard-a", "host" : "shard-a/localhost:3000,localhost:3001",
"state" : 1 }
{ "_id" : "shard-b", "host" : "shard-b/localhost:4000,localhost:4001",
"state" : 1 }
active mongoses:
"3.6.2" : 1
autosplit:
Currently enabled: yes
balancer:
Currently enabled: yes
Currently running: no
Failed balancer rounds in last 5 attempts: 0
Migration Results for the last 24 hours:
No recent migrations
databases:
{ "_id" : "config", "primary" : "config", "partitioned" : true }
-----------------------------------------
查看:
db.getSiblingDB("config").shards.find()
---------------------------------------------
mongos> db.getSiblingDB("config").shards.find()
{ "_id" : "shard-a", "host" : "shard-a/localhost:3000,localhost:3001", "state" :
1 }
{ "_id" : "shard-b", "host" : "shard-b/localhost:4000,localhost:4001", "state" :
1 }
---------------------------------------------
use admin
db.runCommand({listshards:1})
---------------------------------------------
下一部:开启分片;
sh.enableSharding("cloud-docs"); //指定数据库开始分片
db.getSiblingDB("config").databases.find()
//在不改变当前数据库的情况下,切换到config数据库下进行查找;
show dbs 为admin,config,必须是同级数据库。且在同一台服务器上。
下一步:定义片键:
sh.shardCollection("cloud-docs.blog",{username:1,_id:1}) //把数据库cloud-docs的blog集合的username,_id作为片键分片;
db.getSiblingDB("config").collections.find()
use config
db.chunks.count()
db.chunks.findOne()
use config
db.changelog.find() //查看相关的更新日志
db.spreasheets.ensureIndex() //开启分片索引;
--------------------------------------------
仲裁节点开销很少,不需要自己的服务器。
副本集的每个成员,无论是副本节点还是仲裁节点,都需要放在不同的机器上
副本集的仲裁节点是很轻量级的,配置服务器也可能共用,硬件要求是配置集群中的配置服务器都必须放在不同的机器上;
-----------
生产环境中,4台服务器:分片A*2,分片B*2,然后把配置服务器分布在这4台中,然后把仲裁服务器分布在AB二台中;
数据中心恢复6台:前4台按标准主数据,后二台(一个存分片A,一个分片B),分片A中加载配置服务器;这二台就作为备份服务器;
监控:
db.serverStatus(),db.currentOp()
添加分片和开始配置的时候一样的命令;
删除分片:
use admin
db.runCommand({removeshard:shard-1/localhost:3000,localhost:4000});
查看分片:
use config
db.databases.find()
db.runCommand({moveprimary:"test",to:"shard-0-test-rs"});
分片数据的备份与恢复:
连接到mongos,然后mongodump后再用mongorestore恢复。
mongodump -h localhost --port 4000 -d web -c blog
mongorestore -h localhost --port 4000 -d web -c blog
在向mongodb写入时,服务器默认每60S与磁盘强制同步一次,称为后台刷新(background flush)。
lsof | grep mongo | grep data | wc -l
ulimit -Hn 查看硬限制
vim /etc/security/limits.conf
mongod soft nofile 2048
mongod hard nofile 10240
日志会降低写操作的性能,可以在被动副本上开启日志。
mongoimport -d stocks -c values --type csv --headerline stocks.csv
mongoexport -d stocks -c values -o stocks.csv
mongodump -h localhost --port 27017
mongorestore -h localhost --port 27017
mongod --repair
db.runCommand({repairDatabase:1})
--fork 让进程以守护方式运行。
当子对象总是出现在父对象的上下文中时,使用内嵌文档;否则,保存在单独的集合里。
文章示例:
{_id:ObjectId("xx"),
title:"",
text:""}
评论:
{_id:ObjectId("4xxx"),
post_id:ObjectId("xxx"),
username:"zjone",
text:"indeed"
}
db.comments.ensureIndex({post_id:1}) //加索引
mongodb使用数组键来表示多对多的关系:
{_id:ObjectId("a"),title:"epites"}
{_id:ObjectId("b",title:"green flower"}
同时属于这两上分类的文档看起来是这样的:
{_id:ObjectId("y"),
name:"Dragon Orchid",
category_ids:[ObjectId("a"),ObjectId("b")]
}
先找到各个ID,然后用$in操作符查categories集合:
db.categories.find({id:{$in:product['category_ids']}})
db.comments.find({path:/^4d692/})
命名空间会超过24000,一旦超过这个值,就必须分配新的数据库。
mongofiles -d images list //列出数据库images里的文件;
---------------------------------------------------------------------------------
以下为命令行第二次收集脚本:
创建副本集:
---------------------------------
三台机器只是dbpath不同。端口不同;
D:\MongoDB\Server\3.6\bin>mongod --replSet myapp --dbpath c:\data\node1 --port 40000
D:\MongoDB\Server\3.6\bin>mongod --replSet myapp --dbpath c:\data\node1 --port 40001
D:\MongoDB\Server\3.6\bin>mongod --replSet myapp --dbpath c:\data\node1 --port 40002
------------------------------
连接到非仲裁节点后运行:假设当前4000,则
1.rs.initiate()
2.rs.add("localhost:40001")
3.rs.add("localhost:40002",{arbiterOnly:true});
一共三台,二台副本集,一个仲裁;
------------------------------------------------
db.isMaster()
rs.status()
rs.remove("localhost:4000")
rs.slaveOk() //允许副本查询
----------------------------------------------
分片:
------------------------------------------------------
mongod --shardsvr --replSet shard-a --dbpath c:\data\rs-a-1 --port 3000 --logpath c:\data\rs-a-1.log --fork --nojournal
mongod --shardsvr --replSet shard-a --dbpath c:\data\rs-a-2 --port 3001 --logpath c:\data\rs-a-2.log --fork --nojournal
mongod --shardsvr --replSet shard-a --dbpath c:\data\rs-a-3 --port 3002 --logpath c:\data\rs-a-3.log --fork --nojournal
mongod --shardsvr --replSet shard-b --dbpath c:\data\rs-b-1 --port 4000 --logpath c:\data\rs-b-1.log --fork --nojournal
mongod --shardsvr --replSet shard-b --dbpath c:\data\rs-b-2 --port 4001 --logpath c:\data\rs-b-2.log
mongod --shardsvr --replSet shard-b --dbpath c:\data\rs-b-3 --port 4002 --logpath c:\data\rs-b-3.log --fork --nojournal
--------------------------------------------------------
加了二个副本集,不同副本集的名称;然后所有的副本集加了--shardsvr
mongod --configsvr --replSet conf --dbpath c:\data\config-1 --port 27019 --logpath c:\data\config-1.log
mongod --configsvr --replSet conf --dbpath c:\data\config-2 --port 27020 --logpath c:\data\config-2.log
mongod --configsvr --replSet conf --dbpath c:\data\config-3 --port 27021 --logpath c:\data\config-3.log
加了三个配置服务器,也是副本集,而后每个配置服务器加了--configsvr 标识运行;
---------------------------------------------------------
注意副本集:
rs.initiate()
rs.add("123") //依次加三台配置服务器,配置服务器没有仲裁节点。注意上面二个分片也是;
任何的副本集都要初始化才能用。所有的分片配置完成后,用rs.status()查看副本集的状态;
而后所有的配置成功后,启用分片mongos.
------------------------------------------------------------------------