❶ 如何实现mongodb中的sum汇总操作
首先在本地机器上安装并设置MongoDB服务。
从Mongo网站上下载MongoDB,解压到本地目录,比如C:>Mongo
在上一个文件夹内创建数据目录。比如:C:\Mongo\Data
如果数据文件存放在其他地方,那么在用mongod.exe命令启动MongoDB时,需要在命令行加参数—-dbpath
启动服务
MongoDB提供了两种方式:mongod.exe以后台进程启动;mongo.exe启动命令行界面,可做管理操作。这两个可执行文件都位于Mongo\bin目录下;
进入Mongo安装目录的bin目录下,比如:C:> cd Mongo\bin
有两种启动方式,如下:
mongod.exe –dbpath C:\Mongo\data
或者
mongod.exe –config mongodb.config
mongodb.config是Mongo\bin目录下的配置文件,需要在此配置文件中指定数据目录(比如,dbpath= C:\Mongo\Data)的位置。
连接到MongoDB,到这一步,mongo后台服务已经启动,可以通过http://localhost:27017查看。 MongoDB启动运行后,我们接下来看它的聚合函数。
实现聚合函数
在关系数据库中,我们可以在数值型字段上执行包含预定义聚合函数的SQL语句,比如,SUM()、COUNT()、MAX()和MIN()。但是在MongoDB中,需要通过MapRece功能来实现聚合以及批处理,它跟SQL里用来实现聚合的GROUP BY从句比较类似。下一节将描述关系数据库中SQL方式实现的聚合和相应的通过MongoDB提供的MapRece实现的聚合。
为了讨论这个主题,我们考虑如下所示的Sales表,它以MongoDB中的反范式形式呈现。
Sales表
#
列名
数据类型
1
OrderId
INTEGER
2
OrderDate
STRING
3
Quantity
INTEGER
4
SalesAmt
DOUBLE
5
Profit
DOUBLE
6
CustomerName
STRING
7
City
STRING
8
State
STRING
9
ZipCode
STRING
10
Region
STRING
11
ProctId
INTEGER
12
ProctCategory
STRING
13
ProctSubCategory
STRING
14
ProctName
STRING
15
ShipDate
STRING
基于SQL和MapRece的实现
我们提供了一个查询的样例集,这些查询使用聚合函数、过滤条件和分组从句,及其等效的MapRece实现,即MongoDB实现SQL中GROUP BY的等效方式。在MongoDB存储的文档上执行聚合操作非常有用,这种方式的一个限制是聚合函数(比如,SUM、AVG、MIN、MAX)需要通过mapper和recer函数来定制化实现。
MongoDB没有原生态的用户自定义函数(UDFs)支持。但是它允许使用db.system.js.save命令来创建并保存javaScript函数,JavaScript函数可以在MapRece中复用。下表是一些常用的聚合函数的实现。稍后,我们会讨论这些函数在MapRece任务中的使用。
聚合函数
Javascript 函数
SUM
db.system.js.save( { _id : "Sum" ,
value : function(key,values)
{
var total = 0;
for(var i = 0; i < values.length; i++)
total += values[i];
return total;
}});
AVERAGE
db.system.js.save( { _id : "Avg" ,
value : function(key,values)
{
var total = Sum(key,values);
var mean = total/values.length;
return mean;
}});
MAX
db.system.js.save( { _id : "Max" ,
value : function(key,values)
{
var maxValue=values[0];
for(var i=1;i
MIN
db.system.js.save( { _id : "Min" ,
value : function(key,values)
{
var minValue=values[0];
for(var i=1;i
VARIANCE
db.system.js.save( { _id : "Variance" ,
value : function(key,values)
{
var squared_Diff = 0;
var mean = Avg(key,values);
for(var i = 0; i < values.length; i++)
{
var deviation = values[i] - mean;
squared_Diff += deviation * deviation;
}
var variance = squared_Diff/(values.length);
return variance;
}});
STD DEVIATION
db.system.js.save( { _id : "Standard_Deviation"
, value : function(key,values)
{
var variance = Variance(key,values);
return Math.sqrt(variance);
}});
SQL和MapRece脚本在四种不同的用例场景中实现聚合函数的代码片段如下表所示。
1.各地区的平均订单量
下面的查询是用来获取不同地区的平均订单量。
SQL Query
MapRece Functions
SELECT
db.sales.runCommand(
{
maprece : "sales" ,
City,
State,
Region,
map:function()
{ // emit function handles the group by
emit( {
// Key
city:this.City,
state:this.State,
region:this.Region},
// Values
this.Quantity);
},
AVG(Quantity)
rece:function(key,values)
{
var result = Avg(key, values);
return result;
}
FROM sales
GROUP BY City, State, Region
// Group By is handled by the emit(keys, values)
line in the map() function above
out : { inline : 1 } });
2.产品的分类销售总额
下面的查询是用来获取产品的分类销售额,根据产品类别的层级分组。在下面例子中,不同的产品类别作为个体维度,它们也可以被称为更复杂的基于层次的维度。
SQL 查询
MapRece 函数
SELECT
db.sales.runCommand(
{
maprece : "sales" ,
ProctCategory, ProctSubCategory, ProctName,
map:function()
{
emit(
// Key
{key0:this.ProctCategory,
key1:this.ProctSubCategory,
key2:this.ProctName},
// Values
this.SalesAmt);
},
SUM(SalesAmt)
rece:function(key,values)
{
var result = Sum(key, values);
return result;
}
FROM sales
GROUP BY ProctCategory, ProctSubCategory, ProctName
// Group By is handled by the emit(keys, values)
line in the map() function above
out : { inline : 1 } });
3. 一种产品的最大利润
下面的查询是用来获取一个给定产品基于过滤条件的最大利润。
SQL查询
MapRece 函数
SELECT
db.sales.runCommand(
{
maprece : "sales" ,
ProctId, ProctName,
map:function()
{
if(this.ProctId==1)
emit( {
key0:this.ProctId,
key1:this.ProctName},
this.Profit);
},
MAX(SalesAmt)
rece:function(key,values)
{
var maxValue=Max(key,values);
return maxValue;
}
FROM sales
WHERE ProctId=’1’
// WHERE condition implementation is provided in
map() function
GROUP BY ProctId, ProctName
// Group By is handled by the emit(keys, values)
line in the map() function above
out : { inline : 1 } });
4. 总量、总销售额、平均利润
这个场景的需求是计算订单的总数、总销售额和平均利润,订单ID在1到10之间,发货时间在2011年的1月1日到12月31日之间。下面的查询是用来执行多个聚合,比如,在指定年份以及指定的不同区域和产品类别范围里订单的总数、总销售额和平均利润。
SQL 查询
MapRece 函数
SELECT
db.sales.runCommand(
{ maprece : "sales" ,
Region,
ProctCategory,
ProctId,
map:function()
{
emit( {
// Keys
region:this.Region,
proctCategory:this.ProctCategory,
proctid:this.ProctId},
// Values
{quantSum:this.Quantity,
salesSum:this.SalesAmt,
avgProfit:this.Profit} );
}
Sum(Quantity),
Sum(Sales),
Avg(Profit)
rece:function(key,values)
{
var result=
{quantSum:0,salesSum:0,avgProfit:0};
var count = 0;
values.forEach(function(value)
{
// Calculation of Sum(Quantity)
result.quantSum += values[i].quantSum;
// Calculation of Sum(Sales)
result.salesSum += values[i].salesSum;
result.avgProfit += values[i].avgProfit;
count++;
}
// Calculation of Avg(Profit)
result.avgProfit = result.avgProfit / count;
return result;
},
FROM Sales
WHERE
Orderid between 1 and 10 AND
Shipdate BETWEEN ‘01/01/2011’ and
‘12/31/2011’
query : {
"OrderId" : { "$gt" : 1 },
"OrderId" : { "$lt" : 10 },
"ShipDate" : { "$gt" : "01/01/2011" },
"ShipDate" : { "$lt" : "31/12/2011" },
},
GROUP BY
Region, ProctCategory, ProctId
// Group By is handled by the emit(keys, values)
line in the map() function above
LIMIT 3;
limit : 3,
out : { inline : 1 } });
既然我们已经看了在不同业务场景下的聚合函数的代码示例,接下来我们准备来测试这些函数。
测试聚合函数
MongoDB的MapRece功能通过数据库命令来调用。Map和Rece函数在前面章节里已经使用JavaScript实现。下面是执行MapRece函数的语法。
db.runCommand(
{ maprece : <collection>,
map : <mapfunction>,
rece : <recefunction>
[, query : <query filter object>]
[, sort : <sorts the input objects using this key. Useful for
optimization, like sorting by the emit key for fewer reces>]
[, limit : <number of objects to return from collection>]
[, out : <see output options below>]
[, keeptemp: <true|false>]
[, finalize : <finalizefunction>]
[, scope : <object where fields go into javascript global scope >]
[, jsMode : true]
[, verbose : true]
}
)
Where the Output Options include:
{ replace : "collectionName" }
{ merge : "collectionName"
{ rece : "collectionName" }
{ inline : 1}
❷ python mongodb 怎么执行 db.serverStatus 命令
> db.serverStatus();
{
"host" : "localhost.localdomain", --hostname
"version" : "2.4.9", --版本
"process" : "mongod", --进程名称
"pid" : 5099, --进程ID
"uptime" : 1595, --启动时间(单位:S)
"uptimeMillis" : NumberLong(1595123),
"uptimeEstimate" : 1577, --基于MongoDB内部粗粒度定时器的运行时间
"localTime" : ISODate("2014-04-17T06:55:44.924Z"),--server的本地时间
"asserts" : {
"regular" : 0, --server启动以来抛出正规断言(assert 类似于异常处理的形式)总数目
"warning" : 0, --server启动以来抛出的告警总数目
"msg" : 0, --消息断言数目。服务器内部定义的良好字符串错误
"user" : 3, --用户断言数目。用户产生的错误,譬如:磁盘空间满;重复键。
"rollovers" : 0 --server启动以来,assert counters have rolled over的次数
},
"backgroundFlushing" : {
"flushes" : 26, --数据库刷新写到磁盘的次数
"total_ms" : 67, --数据库刷新数据到磁盘花费的微秒数
"average_ms" : 2.576923076923077,--执行单次刷新花费的平均微秒数
"last_ms" : 2, --最后一次执行完成刷新数据到磁盘花费的微秒数
"last_finished" : ISODate("2014-04-17T06:55:09.819Z")--当最后一次刷新数据完成时的时间戳
},
"connections" : {
"current" : 8, --当前活动连接量。连接到server的当前活跃连接数目
"available" : 72, --剩余空闲连接量。剩余的可用连接数目
"totalCreated" : NumberLong(754)
},
"cursors" : {
"totalOpen" : 0, --server为client保持的游标(cursor)总数
"clientCursors_size" : 0,
"timedOut" : 0 --server启动以来游标(cursor)超时的总数
},
"r" : {
"commits" : 30, --上一间隔journal日志发生commit的次数
"journaledMB" : 0, --上一间隔写到journal日志的数据量(单位:MB)
"writeToDataFilesMB" : 0, --上一间隔journal日志写到数据文件的数据量(单位:MB)
"compression" : 0, --
"commitsInWriteLock" : 0, --写锁期间发生commits的次数
"earlyCommits" : 0, --schele时间前请求commit的次数
"timeMs" : {
"dt" : 3064,
"prepLogBuffer" : 0, --准备写journal日志花费的时间
"writeToJournal" : 0, --写journal日志花费的实际时间
"writeToDataFiles" : 0, --journal日志后写数据文件花费的时间
"remapPrivateView" : 0 --The amount of time spent remapping -on-write memory mapped views
}
},
"extra_info" : {
"note" : "fields vary by platform",
"heap_usage_bytes" : 3838448, --此过程中所有的堆字节数目。仅适用于linux
"page_faults" : 31058356 --此过程中访问内存中页面失败的总次数。仅适用于Linux
},
"globalLock" : {
"totalTime" : 1238418105923, --全局锁创建的时间(单位:ms 微秒)
"lockTime" : 75055831911, --全局锁保持的时间(单位:ms 微秒)
"ratio" : 0.06060621332329477, --lockTime和totalTime的比
"currentQueue" : {
"total" : 0, --等待全局锁的队列中操作数目
"readers" : 0, --等待读锁的队列中操作数目
"writers" : 0 --等待写锁的队列中操作数目
},
"activeClients" : {
"total" : 1, --连接到server的当前活动client数目
"readers" : 1, --执行读操作的当前活动client数目
"writers" : 0 --执行写操作的当前活动client数目
}
},
"indexCounters" : {
"accesses" : 196, --Btree索引的访问次数(索引被访问量)
"hits" : 196, --内存中的Btree页的数目。(索引命中量)
"misses" : 0, --内存中不存在的Btree也数目。(索引偏差量)(索引内存访问失败次数)
"resets" : 0, --索引计数器被重置为0的次数
"missRatio" : 0 --索引偏差率(未命中率)
},
"locks" : {
"." : {
"timeLockedMicros" : {
"R" : NumberLong(39089),
"W" : NumberLong(43649)
},
"timeAcquiringMicros" : {
"R" : NumberLong(36077),
"W" : NumberLong(5232)
}
},
"admin" : {
"timeLockedMicros" : {
"r" : NumberLong(818),
"w" : NumberLong(0)
},
"timeAcquiringMicros" : {
"r" : NumberLong(70),
"w" : NumberLong(0)
}
},
"local" : {
"timeLockedMicros" : {
"r" : NumberLong(3414),
"w" : NumberLong(0)
},
"timeAcquiringMicros" : {
"r" : NumberLong(352),
"w" : NumberLong(0)
}
},
"WORKING_COLLECTION" : {
"timeLockedMicros" : {
"r" : NumberLong(1921),
"w" : NumberLong(0)
},
"timeAcquiringMicros" : {
"r" : NumberLong(138),
"w" : NumberLong(0)
}
},
"mydb" : {
"timeLockedMicros" : {
"r" : NumberLong(737),
"w" : NumberLong(0)
},
"timeAcquiringMicros" : {
"r" : NumberLong(92),
"w" : NumberLong(0)
}
},
"test" : {
"timeLockedMicros" : {
"r" : NumberLong(959),
"w" : NumberLong(0)
},
"timeAcquiringMicros" : {
"r" : NumberLong(81),
"w" : NumberLong(0)
}
},
"mdsp" : {
"timeLockedMicros" : {
"r" : NumberLong(261031),
"w" : NumberLong(6093)
},
"timeAcquiringMicros" : {
"r" : NumberLong(4956),
"w" : NumberLong(206)
}
}
},
"network" : {
"bytesIn" : NumberLong("1929833164782"), --发送到数据库的数据总量(bytes)
"bytesOut" : 553137147925, --数据库发出的数据总量(bytes)
"numRequests" : 2475184328 --发送到数据库的请求量
},
"opcounters" : {
"insert" : 687531883, --server启动以来总的insert数据量
"query" : 711010343, --server启动以来总的query数据量
"update" : 0, --server启动以来总的update数据量
"delete" : 0, --server启动以来总的delete数据量
"getmore" : 6484, --server启动以来调用任何游标的getMore总次数
"command" : 1287537 --server启动以来执行其他命令的总次数
},
"opcountersRepl" : {
"insert" : 0,
"query" : 0,
"update" : 0,
"delete" : 0,
"getmore" : 0,
"command" : 0
},
"recordStats" : {
"accessesNotInMemory" : 6,
"pageFaultExceptionsThrown" : 5,
"WORKING_COLLECTION" : {
"accessesNotInMemory" : 0,
"pageFaultExceptionsThrown" : 0
},
"admin" : {
"accessesNotInMemory" : 0,
"pageFaultExceptionsThrown" : 0
},
"local" : {
"accessesNotInMemory" : 0,
"pageFaultExceptionsThrown" : 0
},
"mdsp" : {
"accessesNotInMemory" : 6,
"pageFaultExceptionsThrown" : 5
},
"mydb" : {
"accessesNotInMemory" : 0,
"pageFaultExceptionsThrown" : 0
},
"test" : {
"accessesNotInMemory" : 0,
"pageFaultExceptionsThrown" : 0
}
},
"writeBacksQueued" : false,
"mem" : {
"bits" : 64,
"resident" : 43,
"virtual" : 2326,
"supported" : true,
"mapped" : 992,
"mappedWithJournal" : 1984
},
"metrics" : {
"document" : {
"deleted" : NumberLong(0),
"inserted" : NumberLong(10),
"returned" : NumberLong(1067),
"updated" : NumberLong(20)
},
"getLastError" : {
"wtime" : {
"num" : 0,
"totalMillis" : 0
},
"wtimeouts" : NumberLong(0)
},
"operation" : {
"fastmod" : NumberLong(13),
"idhack" : NumberLong(118),
"scanAndOrder" : NumberLong(122)
},
"queryExecutor" : {
"scanned" : NumberLong(10262)
},
"record" : {
"moves" : NumberLong(0)
},
"repl" : {
"apply" : {
"batches" : {
"num" : 0,
"totalMillis" : 0
},
"ops" : NumberLong(0)
},
"buffer" : {
"count" : NumberLong(0),
"maxSizeBytes" : 268435456,
"sizeBytes" : NumberLong(0)
},
"network" : {
"bytes" : NumberLong(0),
"getmores" : {
"num" : 0,
"totalMillis" : 0
},
"ops" : NumberLong(0),
"readersCreated" : NumberLong(0)
},
"oplog" : {
"insert" : {
"num" : 0,
"totalMillis" : 0
},
"insertBytes" : NumberLong(0)
},
"preload" : {
"docs" : {
"num" : 0,
"totalMillis" : 0
},
"indexes" : {
"num" : 0,
"totalMillis" : 0
}
}
},
"ttl" : {
"deletedDocuments" : NumberLong(0),
"passes" : NumberLong(26)
}
},
"ok" : 1
}
❸ 如何使用mongodb数据库工具
1、基于mongo实现远程连接
[plain] view plain
mongo -u admin -p admin 192.168.0.197:27017/pagedb
通过mongo实现连接,可以非常灵活的选择参数选项,参看命令帮助,如下所示:
[plain] view plain
mongo --help
MongoDB shell version: 1.8.3
usage: mongo [options] [db address] [file names (ending in .js)]
db address can be:
foo foo database on local machine
192.169.0.5/foo foo database on 192.168.0.5 machine
192.169.0.5:9999/foo foo database on 192.168.0.5 machine on port 9999
options:
--shell run the shell after executing files
--nodb don't connect to mongod on startup - no 'db address'
arg expected
--quiet be less chatty
--port arg port to connect to
--host arg server to connect to
--eval arg evaluate javascript
-u [ --username ] arg username for authentication
-p [ --password ] arg password for authentication
-h [ --help ] show this usage information
--version show version information
--verbose increase verbosity
--ipv6 enable IPv6 support (disabled by default)
2、基于MongoDB支持的javascript实现远程连接
当你已经连接到一个远程的MongoDB数据库服务器(例如,通过mongo连接到192.168.0.184),现在想要在这个会话中连接另一个远程的数据库服务器(192.168.0.197),可以执行如下命令:
[plain] view plain
> var x = new Mongo('192.168.0.197:27017')
> var ydb = x.getDB('pagedb');
> use ydb
switched to db ydb
> db
ydb
> ydb.page.findOne()
{
"_id" : ObjectId("4eded6a5bf3bfa0014000003"),
"content" : "巴黎是浪漫的城市,可是...",
"pubdate" : "2006-03-19",
"title" : "巴黎:从布鲁塞尔赶到巴黎",
"url" : "http://france.bytravel.cn/Scenery/528/cblsegdbl.html"
}
上述通过MongoDB提供的JavaScript脚本,实现对另一个远程数据库服务器进行连接,操作指定数据库pagedb的page集合。
如果启用了安全认证模式,可以在获取数据库连接实例时,指定认证账号,例如:
[plain] view plain
> var x = new Mongo('192.168.0.197:27017')
> var ydb = x.getDB('pagedb', 'shirdrn', '(jkfFS$343$_\=\,.F@3');
> use ydb
switched to db ydb
❹ MongoDB批量操作文档(bulkWrite) --- 2022-04-03
本章介绍,通过mongo shell,批量操作(bulkWrite)MongoDB文档数据。这里的批量操作不仅仅是前面章节提到的批量更新文档,MongoDB批量操作支持同时执行一批写操作,写操作包括:插入文档、更新文档、删除文档。
mongo shell通过db.collection.bulkWrite()函数执行批量操作。
批量操作支持下面写操作自由组合。
说明:
下面看一个综合里面,批量执行一批文档写操作。
❺ java怎么做到使用mongodb的原生命令来执行操作
public class MongoDBJDBC {
public static void main(String[] args) {
try {
// 实例化Mongo对象,连接27017端口
Mongo mongo = new Mongo("localhost", 27017);
// 连接名为yourdb的数据库,假如数据库不存在的话,mongodb会自动建立
DB db = mongo.getDB("test");
// Get collection from MongoDB, database named "yourDB"
// 从Mongodb中获得名为yourColleection的数据集合,如果该数据集合不存在,Mongodb会为其新建立
DBCollection collection = db.getCollection("test1");
// 使用BasicDBObject对象创建一个mongodb的document,并给予赋值。
BasicDBObject document = new BasicDBObject();
//document.put("id", 1001);
//document.put("msg", "hello world mongoDB in Java");
// 将新建立的document保存到collection中去
//collection.insert(document);
// 创建要查询的document
❻ 在windows下mongodb怎么执行js脚本
以前并没有留意用JavaScript管理MongoDB,不过这个还是很有用的功能。特别是可以写一些定时脚本,定期检查数据库,做一些管理任务。
1. mongo shell中可以直接运行JavaScript代码
比如:
> new Date()
ISODate("2013-12-12T07:37:00.074Z")
> x = new Date();
ISODate("2013-12-12T07:37:05.724Z")
> x.getTime();
1386833825724
> var y = Date();
> y.getTime()
Thu Dec 12 15:37:26.805 TypeError: Object Thu Dec 12 2013 15:37:21 GMT+0800 (CST) has no method 'getTime'
>
如果想获得epoch以来的毫秒数,必须用new Date()。
而Date(),似乎就只是一个函数,返回一个字符串而已。没什么大作用,反而容易混淆人的概念。
b. Date对象提供了getTime()
2. 查询语句中,可以用$where operator来执行JavaScript函数, 比如:
db.display.find({$and: [{$where: function() {return new Date().getTime(
3. 可以将代码写到一个js文件中,然后用mongo命令执行
比如:下面将当前时间和last_active_time字段的值的差大于300秒的,状态为offline的document找出来,并显示。
cursor = db.display.find({$and: [{$where: function() {return new Date().getTime() / 1000 - this.last_active_time > 300}}, {status: "offline"}]})
while (cursor.hasNext()) {
printjson(cursor.next());
}
然后这样执行:
mongo localhost/mydb test.js
❼ mongodb数据库批量插入海量数据时为什么有少部分数据丢失
可以这么排查下。
1.先少批量执行看是否有异常
》确认是否是语法问题
2.把大批量分n批量执行看是否是某一批有问题
》确认是否是操作超时导致
》确认是否是某些特殊数据导致
3.确认是否是某批量里面的数据有异常导致异常退出没写入之后的数据
》确认是否是代码的严密性问题,异常try catch
4.生产环境上只能多输出日志来确认问题
5.可以在本地模拟下生产环境
❽ MongoDB是什么,怎么用看完你就知道了
MongoDB是一款为web应用程序和互联网基础设施设计的数据库管理系统。没错MongoDB就是数据库,是NoSQL类型的数据库。
(1)MongoDB提出的是文档、集合的概念,使用BSON(类JSON)作为其数据模型结构,其结构是面向对象的而不是二维表,存储一个用户在MongoDB中是这样子的。
使用这样的数据模型,使得MongoDB能在生产环境中提供高读写的能力,吞吐量较于mysql等SQL数据库大大增强。
(2)易伸缩,自动故障转移。易伸缩指的是提供了分片能力,能对数据集进行分片,数据的存储压力分摊给多台服务器。自动故障转移是副本集的概念,MongoDB能检测主节点是否存活,当失活时能自动提升从节点为主节点,达到故障转移。
(3)数据模型因为是面向对象的,所以可以表示丰富的、有层级的数据结构,比如博客系统中能把“评论”直接怼到“文章“的文档中,而不必像myqsl一样创建三张表来描述这样的关系。
(1)文档数据类型
SQL类型的数据库是正规化的,可以通过主键或者外键的约束保证数据的完整性与唯一性,所以SQL类型的数据库常用于对数据完整性较高的系统。MongoDB在这一方面是不如SQL类型的数据库,且MongoDB没有固定的Schema,正因为MongoDB少了一些这样的约束条件,可以让数据的存储数据结构更灵活,存储速度更加快。
(2)即时查询能力
MongoDB保留了关系型数据库即时查询的能力,保留了索引(底层是基于B tree)的能力。这一点汲取了关系型数据库的优点,相比于同类型的NoSQL redis 并没有上述的能力。
(3)复制能力
MongoDB自身提供了副本集能将数据分布在多台机器上实现冗余,目的是可以提供自动故障转移、扩展读能力。
(4)速度与持久性
MongoDB的驱动实现一个写入语义 fire and forget ,即通过驱动调用写入时,可以立即得到返回得到成功的结果(即使是报错),这样让写入的速度更加快,当然会有一定的不安全性,完全依赖网络。
MongoDB提供了Journaling日志的概念,实际上像mysql的bin-log日志,当需要插入的时候会先往日志里面写入记录,再完成实际的数据操作,这样如果出现停电,进程突然中断的情况,可以保障数据不会错误,可以通过修复功能读取Journaling日志进行修复。
(5)数据扩展
MongoDB使用分片技术对数据进行扩展,MongoDB能自动分片、自动转移分片里面的数据块,让每一个服务器里面存储的数据都是一样大小。
MongoDB核心服务器主要是通过mongod程序启动的,而且在启动时不需对MongoDB使用的内存进行配置,因为其设计哲学是内存管理最好是交给操作系统,缺少内存配置是MongoDB的设计亮点,另外,还可通过mongos路由服务器使用分片功能。
MongoDB的主要客户端是可以交互的js shell 通过mongo启动,使用js shell能使用js直接与MongoDB进行交流,像使用sql语句查询mysql数据一样使用js语法查询MongoDB的数据,另外还提供了各种语言的驱动包,方便各种语言的接入。
mongomp和mongorestore,备份和恢复数据库的标准工具。输出BSON格式,迁移数据库。
mongoexport和mongoimport,用来导入导出JSON、CSV和TSV数据,数据需要支持多格式时有用。mongoimport还能用与大数据集的初始导入,但是在导入前顺便还要注意一下,为了能充分利用好mongoDB通常需要对数据模型做一些调整。
mongosniff,网络嗅探工具,用来观察发送到数据库的操作。基本就是把网络上传输的BSON转换为易于人们阅读的shell语句。
因此,可以总结得到,MongoDB结合键值存储和关系数据库的最好特性。因为简单,所以数据极快,而且相对容易伸缩还提供复杂查询机制的数据库。MongoDB需要跑在64位的服务器上面,且最好单独部署,因为是数据库,所以也需要对其进行热备、冷备处理。
因为本篇文章不是API手册,所有这里对shell的使用也是基础的介绍什么功能可以用什么语句,主要是为了展示使用MongoDB shell的方便性,如果需要知道具体的MongoDB shell语法可以查阅官方文档。
创建数据库并不是必须的操作,数据库与集合只有在第一次插入文档时才会被创建,与对数据的动态处理方式是一致的。简化并加速开发过程,而且有利于动态分配命名空间。如果担心数据库或集合被意外创建,可以开启严格模式。
以上的命令只是简单实例,假设如果你之前没有学习过任何数据库语法,同时开始学sql查询语法和MongoDB 查询语法,你会发现哪一个更简单呢?如果你使用的是java驱动去操作MongoDB,你会发现任何的查询都像Hibernate提供出来的查询方式一样,只要构建好一个查询条件对象,便能轻松查询(接下来会给出示例),博主之前熟悉ES6,所以入手MongoDB js shell完成没问题,也正因为这样简洁,完善的查询机制,深深的爱上了MongoDB。
使用java驱动链接MongoDB是一件非常简单的事情,简单的引用,简单的做增删改查。在使用完java驱动后我才发现spring 对MongoDB 的封装还不如官方自身提供出来的东西好用,下面简单的展示一下使用。
这里只举例了简单的链接与简单的MongoDB操作,可见其操作的容易性。使用驱动时是基于TCP套接字与MongoDB进行通信的,如果查询结果较多,恰好无法全部放进第一服务器中,将会向服务器发送一个getmore指令获取下一批查询结果。
插入数据到服务器时间,不会等待服务器的响应,驱动会假设写入是成功的,实际是使用客户端生成对象id,但是该行为可以通过配置配置,可以通过安全模式开启,安全模式可以校验服务器端插入的错误。
要清楚了解MongoDB的基本数据单元。在关系型数据库中有带列和行的数据表。而MongoDB数据的基本单元是BSON文档,在键值中有指向不定类型值的键,MongoDB拥有即时查询,但不支持联结操作,简单的键值存储只能根据单个键来获取值,不支持事务,但支持多种原子更新操作。
如读写比是怎样的,需要何种查询,数据是如何更新的,会不会存在什么并发问题,数据结构化的程度是要求高还是低。系统本身的需求决定mysql还是MongoDB。
在关于schema 的设计中要注意一些原则,比如:
数据库是集合的逻辑与物理分组,MongoDB没有提供创建数据库的语法,只有在插入集合时,数据库才开始建立。创建数据库后会在磁盘分配一组数据文件,所有集合、索引和数据库的其他元数据都保存在这些文件中,查阅数据库使用磁盘状态可通过。
集合是结构上或概念上相似得文档的容器,集合的名称可以包含数字、字母或 . 符号,但必须以字母或数字开头,完全。
限定集合名不能超过128个字符,实际上 . 符号在集合中很有用,能提供某种虚拟命名空间,这是一种组织上的原则,和其他集合是一视同仁的。在集合中可以使用。
其次是键值,在MongoDB里面所有的字符串都是UTF-8类型。数字类型包括double、int、long。日期类型都是UTC格式,所以在MongoDB里面看到的时间会比北京时间慢8小时。整个文档大小会限制在16m以内,因为这样可以防止创建难看的数据类型,且小文档可以提升性能,批量插入文档理想数字范围是10~200,大小不能超过16MB。
(1)索引能显着减少获取文档的所需工作量,具体的对比可以通过 .explain()方法进行对比
(2)解析查询时MongoDB通过最优计划选择一个索引进行查询,当没有最适合索引时,会先不同的使用各个索引进行查询,最终选出一个最优索引做查询
(3)如果有一个a-b的复合索引,那么仅针对a的索引是冗余的
(4)复合索引里的键的顺序是很重要的
(1)单键索引
(2)复合索引
(3)唯一性索引
(4)稀疏索引
如索引的字段会出现null的值,或是大量文档都不包含被索引的键。
如果数据集很大时,构建索引将会花费很长的时间,且会影响程序性能,可通过
当使用 mongorestore 时会重新构建索引。当曾经执行过大规模的删除时,可使用
对索引进行压缩,重建。
(1)查阅慢查询日志
(2)分析慢查询
注意新版本的MongoDB 的explain方法是需要参数的,不然只显示普通的信息。
本节同样主要简单呈现MongoDB副本集搭建的简易性,与副本集的强壮性,监控容易性
提供主从复制能力,热备能力,故障转移能力
实际上MongoDB对副本集的操作跟mysql主从操作是差不多的,先看一下mysql的主从数据流动过程
而MongoDB主要依赖的日志文件是oplog
写操作先被记录下来,添加到主节点的oplog里。与此同时,所有从结点复制oplog。首先,查看自己oplog里最后一条的时间戳;其次,查询主节点oplog里所有大于此时间戳的条目;最后,把那些条目添加到自己的oplog里并应用到自己的库里。从节点使用长轮询立即应用来自主结点oplog的新条目。
当遇到以下情况,从节点会停止复制
local数据库保存了所有副本集元素据和oplog日志
可以使用以下命令查看复制情况
每个副本集成员每秒钟ping一次其他所有成员,可以通过rs.status()看到节点上次的心跳检测时间戳和 健康 状况。
这个点没必要过多描述,但是有一个特殊场景,如果从节点和仲裁节点都被杀了,只剩下主节点,他会把自己降级成为从节点。
如果主节点的数据还没有写到从库,那么数据不能算提交,当该主节点变成从节点时,便会触发回滚,那些没写到从库的数据将会被删除,可以通过rollback子目录中的BSON文件恢复回滚的内容。
(1)使用单节点链接
只能链接到主节点,如果链接到从节点的话,会被拒绝写入操作,但是如果没有使用安全模式,因为mongo的fire and forget 特性,会把拒绝写入的异常给吃掉。
(2)使用副本集方式链接
能根据写入的情况自动进行故障转移,但是当副本集进行新的选举时,还是会出现故障,如果不使用安全模式,依旧会出现写不进去,但现实成功的情况。
分片是数据库切分的一个概念实现,这里也是简单总结为什么要使用分片以及分片的原理,操作。
当数据量过大,索引和工作数据集占用的内存就会越来越多,所以需要通过分片负载来解决这个问题
(1)分片组件
(2)分片的核心操作
分片一个集合:分片是根据一个属性的范围进行划分的,MongoDB使用所谓的分片键让每个文档在这些范围里找到自己的位置
块:是位于一个分片中的一段连续的分片键范围,可以理解为若干个块组成分片,分片组成MongoDB的全部数据
(3)拆分与迁移
块的拆分:初始化时只有一个块,达到最大块尺寸64MB或100000个文档就会触发块的拆分。把原来的范围一分为二,这样就有了两个块,每个块都有相同数量的文档。
迁移:当分片中的数据大小不一时会产生迁移的动作,比如分片A的数据比较多,会将分片A里面的一些块转移到分片B里面去。分片集群通过在分片中移动块来实现均衡,是由名为均衡器的软件进程管理的,任务是确保数据在各个分片中保持均匀分布,当集群中拥有块最多的分片与拥有块最少分片的块差大于8时,均衡器就会发起一次均衡处理。
启动两个副本集、三个配置服务器、一个mongos进程
配置分片
(1)分片查询类型
(2)索引
分片集合只允许在_id字段和分片键上添加唯一性索引,其他地方不行,因为这需要在分片间进行通信,实施起来很复杂。
当创建分片时,会根据分片键创建一个索引。
(1)分片键是不可修改的、分片键的选择非常重要
(2)低效的分片键
(3)理想的分片键
(1)部署拓扑
根据不同的数据中心划分
这里写图片描述
(2)最低要求
(3)配置的注意事项
需要估计集群大小,可使用以下命令对现有集合进行分片处理
(4)备份分片集群
备份分片时需要停止均衡器
(1)部署架构
使用64位机器、32位机器会制约mongodb的内存,使其最大值为1.5GB
(2)cpu
mongodb 只有当索引和工作集都可放入内存时,才会遇到CPU瓶颈,CPU在mongodb使用中的作用是用来检索数据,如果看到CPU使用饱和的情况,可以通过查询慢查询日志,排查是不是查询的问题导致的,如果是可以通过添加索引来解决问题
mongodb写入数据时会使用到CPU,但是mongodb写入时间一次只用到一个核,如果有频繁的写入行为,可以通过分片来解决这个问题
(3)内存
大内存是mongodb的保障,如果工作集大小超过内存,将会导致性能下降,因为这将会增加数据加载入内存的动作
(4)硬盘
mongodb默认每60s会与磁盘强制同步一次,称为后台刷新,会产生I/O操作。在重启时mongodb会将磁盘里面的数据加载至内存,高速磁盘将会减少同步的时间
(5)文件系统
使用ext4 和 xfs 文件系统
禁用最后访问时间
(6)文件描述符
linux 默认文件描述符是1024,需要大额度的提升这个额度
(7)时钟
mongodb各个节点服务器之间使用ntp服务器
(1)绑定IP
启动时使用 - -bind_ip 命令
(2)身份验证
启动时使用 - -auth 命令
(3)副本集身份认证
使用keyFile,注意keyFile文件的权限必须是600,不然会启动不起来
(1)拓扑结构
搭建副本集至少需要两个节点,其中仲裁结点不需要有自己的服务器
(2)Journaling日志
写数据时会先写入日志,而此时的数据也不是直接写入硬盘,而是写入内存
但是Journaling日志会消耗内存,所以可以在主库上面关闭,在从库上面启动
可以单独为Journaling日志使用一块固态硬盘
在插入时,可以通过驱动确保Journaling插入后再反馈,但是会非常影响性能。
logpath 选项指定日志存储地址
-vvvvv 选项(v越多,输出越详细)
db.runCommand({logrotare:1}) 开启滚动日志
(1)serverStatus
这里写图片描述
(2)top
(3)db.currentOp()
动态展示mongodb活动数据
占用当前mongodb监听端口往上1000号的端口
(1)mongomp
把数据库内容导出成BSON文件,而mongorestore能读取并还原这些文件
(2)mongorestore
把导出的BSON文件还原到数据库
(3)备份原始数据文件
可以这么做,但是,操作之前需要进行锁库处理 db.runCommand({fsync:1,lock:true})
db.$cmd.sys.unlock.findOne() 请求解锁操作,但是数据库不会立刻解锁,需要使用db.currentOp()验证。
(1)修复
mongd --repair 修复所有数据库
db.runCommand({repairDatabase:1}) 修复单个数据库
修复就是根据Jourling文件读取和重写所有数据文件并重建各个索引
(2)压紧
压紧,会重写数据文件,并重建集合的全部索引,需要停机或者在从库上面运行,如果需要在主库上面运行,需要添加force参数 保证加写锁。
(1)监控磁盘状态
(2)为提升性能检查索引和查询
总的来说,扫描尽可能少的文档。
保证没有冗余的索引,冗余的索引会占用磁盘空间、消耗更多的内存,在每次写入时还需做更多工作
(3)添加内存
dataSize 数据大小 和 indexSize 索引大小,如果两者的和大于内存,那么将会影响性能。
storageSize超过dataSize 数据大小 两倍以上,就会因磁盘碎片而影响性能,需要压缩。
❾ MongoDB怎样批量执行命令
没有这种操作,因为MongoDB的底层就不支持这种操作。
从MongoDB的oplog模式中可以看出,MongoDB的每次op都是独立执行的最小单元,因此,不会存在多个op组合成一个执行的情况。因此在各种API中都不会存在这种批量插入的操作。