Mongodb操作与基本特性

    本文主要介绍Mongodb中CRUD常用操作、存储引擎、数据模型,以及如何使用java Driver。

 

一、BSON

    Mongodb中数据存储格式为BSON,和JSON非常类似,可以说在整体的结构几乎一样,只不过BSON定义了更多的数据类型,这对面向对象编程语言非常友好。

{
    "_id": {
        "$oid": "55f6c87fdefdd10de72fc024"
    },
    "name": "zhangsan",
    "age": 30,
    "is_alive": true,
    "addresses": [
        "beijing",
        "shanghai"
    ],
    "created": {
        "$date": 1442236543707
    }
}

    文档格式大概如上所示,如果数据类型时JSON不支持的,那么数据类型也将写入文档中,比如date。BSON中有2个比较特殊的类型,其中date对应java中的Date,array对于java中List。其他类型比如boolean,string,int等与java都一一对应。

 

    在mongodb中,一条数据称为一个document,其API类为org.bson.Document,当然Document也是Bson的子类,同时也实现了Map接口,其内部有一个LinkedHashMap作为数据支撑(所以mongodb中字段是有顺序的)。

Document user = new Document()
                .append("name", "zhangsan")
                .append("age", 30)
                .append("is_alive",true)
                .append("addresses", Arrays.asList("beijing","shanghai"))
                .append("created", new Date());

    上述就是创建一个Document的过程,这和操作一个Map其实并没有太大区别。

 

二、java driver示例

    如下简单展示如何使用mongodb java客户端开发,因为下面的例子都是基于JAVA的。具体参见:“mongodb java”

<dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongodb-driver</artifactId>
    <version>3.0.3</version>
</dependency>

    创建MongoClient的方式有多种,可以参看MongoClient的构造方法即可。最终归结来由2个主要方式,一个是MongClient + MongoClientOptions,另一个是MongClient + conenctionString。例子如下,如果想在spring环境中使用,请你继续封装。关于授权登陆,SSL方面,稍后会专门介绍,此处仅为示例:

MongoClient mongoClient = new MongoClient("127.0.0.1", 27017);
//MongoClient mongoClient = new MongoClient(new MongoClientURI("mongodb://127.0.0.1:27017"));
MongoDatabase db = mongoClient.getDatabase("test");//获取DB
MongoCollection<Document> collection = db.getCollection("user");//获取collection(表)
//通过collection进行CRUD操作

 

    CRUD的例子将会在下文中列举。

 

三、Read操作

    即从mongodb中读取一条或者多条数据,可以在query中使用多种复合查询条件,这种查询条件的组合类似于SQL,我们也可以使用“projection”过滤器来指定需要返回的结果中包含(不包含)哪些字段,以提升IO效率,因为Mongodb可以使用众多的类似于SQL的查询操作,而且支持多种indexes,这或许就是mongodb的亮点所在。(Mongodb之上的SQL引擎:Drill,即使用sql查询mongodb数据)

MongoCollection<Document> collection = db.getCollection("user");//获取collection(表)
//通过collection进行CRUD操作
Bson parent = Filters.eq("name", "zhangsan");
parent = Filters.and(parent,Filters.gt("age", 10));
MongoCursor<Document> cursor = collection.find(parent).sort(new Document("age", 1)).skip(10).limit(5).iterator();
try {
	while (cursor.hasNext()) {
		Document item = cursor.next();
		System.out.println(item.toJson());
	}
} finally {
	cursor.close();//must be
}

    上面例子就是一个典型的query,我们基本上可以通过多种组合,即可完成复杂的查询。我们使用了Filters API来构建查询条件,这是一个便捷的方式。当然开发者也可以自己使用mongodb的“比较指令”来自己封装:

Document filter = new Document("name",new Document("$eq","zhangsan"));

    自己封装不仅繁琐而且易于出错,建议使用Filters。

 

    1、比较符

    mongodb支持如下几种比较操作,它们均可以在query的查询条件中:$eq(相等,逐字节比较),$gt(大于),$gte(大于等于),$lt(小于),$lte(小于等于),$ne(不等于),$in(值是否在指定的数组中),$nin(值不在制定的数组中)。

    2、逻辑判断符

    $or:逻辑or,如果document匹配多个条件判断中的一个或者多个,则将此document返回。

    $and:逻辑and,document必须匹配全部的判断条件。

    $not:逻辑!,$and取反,如果document不匹配条件,则返回此document。比如:"age":{$not:{$gt:16}}表示“获取age不大于16的document”,它的内部检测过程就是“如果此document存在age字段,且大于16的,一律不返回”,言外之意是:如果document中不包含age字段,或者age的值小于等于16的均会返回。

    $nor:not or。

    3、元素

    $exists:检测文档中是否存在此字段,比如: "name":{$exists:true}表示如果name字段存在,则返回此文档。

    $type:检测文档中字段的类型,比如:"age":{$type:16}表示如果age字段的类型为int则返回此文档,参见BSON Types

   4、数组

    $all:如果字段的值是数组,$all表示此数组中包含指(不一定必须等于)定的所有元素。比如:"addresses":{$all:["beijing","shanghai"]},首先addresses字段值是一个数组,且同时包含“beijing”、“shanghai”两个元素。   

    $elemMatch:数组中至少包含一个元素同时满足条件,比如:"item":{$elemMatch:{$gt:25,$lt:60}},这表示数组item至少包含一个元素大于25且小于60,item:[15,26,70]这个文档就符合要求,而item:[16,62]就不符合要求。

    $size:数组的元素个数满足条件,比如"item":{$size:2}则会返回item中元素个数为2的文档。

    此外,我们可以在表达式中指定index位置来获取数组中的元素:

collection.find(new Document("addresses.0","beijing"))

    表示获取addresses这个数组中第0个位置的元素值为“beijing”的文档。

 

    5、运算与表达式

    $mod:取模运算,比如"price":{$mod:[4,0]}即获取price与4取模为0的文档。

    $regex:正则匹配,基于PCRE,首先参与匹配的field必须建立索引,否则性能受限。语法样例为:{<field>:{$regex:/pattern/,$options:'<options>'}},比如{"name":{$regex:/^liu/,$option:i}}表示查询去name字段值以“liu”开头的文档。其中$regex表示正则表达式,表达式需要以“/”开头和结尾,$option表示辅助选项,它有4个可选值:“i”表示不区分大小写;“m”表示“多行匹配”,其中行符为"\n";“s”表示“.”符号可以匹配所有字符包括换行符,“x”表示忽略空白符。

    表达式可以简写为{<field>:{$regex:/pattern/options}}。如果表达式中不包含正则匹配符(比如$,^,*等,参见PCRE),表示字符串完全匹配,而且正则表达式可以在字符串比较操作中直接使用。

    比如:"name":/zhangsan/,表示name中包含完整字符串"zhangsan"的文档,"name":/^zhang/,表示以zhang开头的文档。

    "name"/^zhang/i,这是正则的简写形势,表示以zhang开头且不区分大小写。

    "description":"/^S/m",我们指定了选项值为m,它可以匹配多行字符串,只要每行为S开头即可。比如文档"description":"Fist line \nSecond line"将匹配成功。

 

    6、projection

    $:这个符号,很特殊,对于query而言,用于获数组中匹配比较表达的第一个元素。这是一个“projection”操作,稍后我们会详解。比如文档"number":[16,31,6,88],对于描述“如果number中存在30~100的元素,则获取第一个匹配的元素”,我们可以使用$与elemMatch:

Document filter = new Document()
                .append("$gt",30)
                .append("$lt",100);
MongoCursor<Document> cursor = collection.find(Filters.elemMatch("number",filter)).projection(new Document("number.$",1)).iterator();

   结果将输出:{"number":[31]}。projection表示需要在结果中包含(不包含)那些字段。

    projection是mongodb提供了用于过滤返回字段的操作,1表示包含字段,0表示不包含。

    $slice:限定返回结果中数组元素的数量,可以只返回数据的起止位置之间的元素。

Document document = new Document("number",new Document("$slice",Arrays.asList(2,5)));
MongoCursor<Document> cursor = collection.find().projection(document).iterator();

    如上例,对于number数组,只需返回位置2之后的5个元素,默认起始位置为0,语法为$slice:[skip,limit]。"number":{$slice:2}则表示返回位置2之后的元素,其中skip可以为负数,表示从尾部计数,比如$slice:[-20,5]表示从尾部计数第20个开始取5个元素。

 

    7、find()方法:返回一个FindIterable对象,我们通常根据FindIterable获取一个Cursor,我们就可以遍历此cursor,依次读取结果集,FindIterable中有很多方法有用的方法:

    1)batchSize(int size):每次网络请求返回的document条数,比如你需要查询500条数据,mongodb不会一次性全部load并返回给client,而是每次返回batchSize条,遍历完之后后再通过网路IO获取直到cursor耗尽。默认情况下,首次批量获取101个document或者1M的数据,此后每次4M,当然我们可以通过此方法来覆盖默认值,如果文档尺寸较小,则建议batchSize可以大一些。

    2)skip(int number)、limit(int number):同SQL中的limit字句,即表示在符合匹配规则的结果集中skip一定数量的document,并最终返回limit条数据。可以实现分页查询。

    3)maxTime(int time,TimeUnit unit):表示此次操作保持的最长时间,即server端保持cursor状态的最长时间,如果超时server端将移除此cursor,即在此通过此cursor遍历数据将会error。

    4)sort(Bson bson):根据指定field排序,参与排序的字段最好是索引,如果不是,将会在内存中排序,如果参与排序的数据尺寸大于32M,将会抛出error。1表示正序,-1表示倒叙,比如"age":1表示按照age正序排序。

    5)noCursorTimeout(boolean timeout):如果cursor空闲一定时间后(10分钟),server端是否将其移除,默认为false,即server会将空闲10分钟的cursor移除以节约内存。如果为true,则表示server端不需要移除空闲的cursor,而是等待用户手动关闭。无论如何,开发者都需要注意,手动关闭cursor。

    6)partial(boolean partial):对于sharding集群,如果一个或者多个shard不可达,是否允许返回部分数据(只从正常的shard中获取数据)。

    7)cursorType():指定cursor类型,当cursor遍历完毕后是否关闭cursor,默认是关闭,无论何时都建议手动关闭cursor(不管是否耗尽curosr);当然有些开发场景可能需要保持cursor的活性,遍历到cursor的最后一条后,不关闭cursor,继续等待,此后一段时间内如果有新数据插入到cursor之后,则可以继续遍历,这就是Tailable Cursor,通常对于Capped Collection中使用。目前支持支持3种类型的Cursor:NonTailable、Tailable、TailableAwait。

    8)projection(Bson bson):限定返回结果中需要包含的filed或者数组元素。在6)中我们已经看到相关的几个例子。默认情况下,将会返回document的所有字段,1表示包含,0表示不包含。

MongoCursor<Document> cursor = collection.find().projection(new Document("name",0)).iterator();

    表示文档中不包含name字段。

MongoCursor<Document> cursor = collection.find().projection(new Document("address",1)).iterator();

     表示结果中只包含address字段。通过例子比较,我们会发现“包含”和“不包含”互为排斥,通常只会在projection使用一种。

 

    8、内嵌文档:内嵌文档可以通过"."来表达路径,比如文档:

{
    "_id": 1,
    "addressess":{
        "zip_code":100010,
         "city":"beijing"
    }
}

    可以通过查询内部文档: 

collection.find(new Document("addresses.zip_code",10010));

 

    9、查询优化:和其他数据库一样,mongodb也支持查询优化,也支持辅助索引,同时_id字段是唯一索引,通常我们需要根据查询条件,来创建合适的辅助索引,比如在单字段索引或者多个字段的组合索引,索引的作用最终是避免对整个collection(磁盘IO)全量扫描。合适的索引将会匹配较少比例的数据,否则不当的索引事实上并不能有效的筛选数据,比如一个字段status,最多有3个不同的值,那么对status建立索引并不能提高查询性能,因为query根据status不能过滤掉大量数据,这就是“基准”。

 

    覆盖查询(Cover query)表示查询使用了索引,且所有需要返回的字段都是索引的一部分,这意味着只需要索引就可以筛选并获得结果内容,这一过程均会在内存中进行,无需进行磁盘查询整个document,这是性能比较高的。不过,如果对数组做索引,即“multi-key index”将不支持覆盖查询;如果查询条件或者projection包含了内置document字段,则也不支持覆盖查询。比如文档:

    {"_id":1,user:{login:"testuser"},如果对"user.login"建立索引,那么如下查询仍将不会使用查询覆盖:

    

collection.find(Filters.eq("user.login","testuser")).projection(new Document("userlogin",1))

    不过这个查询仍然会使用到user.login索引,但不会覆盖查询。 

    在sharding环境中,如果index中不包含shard key,将不支持覆盖查询;_id除外,如果查询中仅用_id查询且返回结果中只包含_id字段,仍会使用覆盖查询。

 

    mongodb也提供了explain,用来分析query的查询计划,通常我们可以使用explain来判定此query的性能。具体请参看explain结果分析以及explain介绍。

 

    9、分布式查询:mongodb的分布式模型分为replica set和sharded cluster。

    sharded集群中将read根据sharding key(分片键)转发到指定的shard节点,read操作非常高效;当然如果query中没有包含sharding key,那么此次read将会被转发到所有的shard节点上,并有mongos server负责merge结果(包括排序),所以这种情况性能较差(俗称scatter、gather),对于大型集群,这种查询通常是不可行的。

 

    对于replica set而言,只是涉及到将read操作路由到哪个secondary上,默认情况下,read请求总是在primary上发生,我们可以通过指定“read preference mode”来调整这一行为。

collection.withReadPreference(ReadPreference.secondaryPreferred()).find();

    上述代码表示尽可能从 secondary上读取,如果所有的secondary都失效则从primary上读取。可以实现“读写分离”。目前支持的read模式:

    1)primary:读操作只发生在primary上,默认的read模式。如果primary失效,则返回error。

    2)primaryPreferred:读操作发生在primary上,如果primary失效,则由secondary接收read请求。这是一种比较良好的模式,

    3)secondary:读操作只发生在secondary上,如果所欲哦的secondary都失效,则返回error。

    4)secondaryPreferred:读操作通常发生在secondary上,如果所有的secondary都失效,则由primary接收read请求。

    5)nearest:读取“最近”的节点,mongodb客户端将评估与每个节点的网络延迟,有限选择延迟最小的节点,primary和secondary都有可能接收到read请求(不同的Client或许延迟不同)。

 

四、Write操作

    write操作包括insert、update,replace,remove四种类型,需要清楚的是mongodb并不支持事务,所以如果write操作影响多条document,那么它们之间的变更并非原子性的,即有可能几条document修改(插入)成功但是其他的或许失败;对于一个document而言,是原子性的,不可能存在一个documnet被部分更新的情况。

    

Document document = new Document()
                .append("number", Arrays.asList(15, 20, 44, 60, 80));
collection.insertOne(document);

    对于insert操作,mongodb会检测文档中是否指定了_id,如果没有指定,server端将会根据一定的算法(ObjectId方法)生成一个并保存,如果开发者自己指定_id,需要确保全局唯一。

 

    update操作可以根据查询条件,更新相应的一条或者多条documents。java Driver中提供了updateOne、updateMany、findAndModify等方法。可以在UpdateOptions中指定upsert来实现“如果存在就更新,否则就插入”的语义:

UpdateResult result = collection.updateOne(Filters.eq("name", "zhangsan"),
                new Document("$set",new Document("modified", new Date())),
                new UpdateOptions().upsert(true));
if(result.getModifiedCount() > 0) {
     System.out.println("found and modified!");
 }

    

    replace就是“替换”,将整个文档,全部替换为指定的document。

 

    1、$isolated:隔离,这涉及到mongodb lock机制,mongodb允许同时有多个read、write操作交错执行,当write操作影响到多条记录时,我们可以使用"$islolated"避免这种情况,此时write操作将持有全局锁,直到此操作涉及到的所有的document都变更完毕,此期间其他client将不会看到变更的数据,直到此write操作结束或者error退出。isolated将会较长时间的持有lock,会对整体的并发能力带来负面影响;此外,它并不表达事务中的“all-or-nothing”语义,即如果write操作更新一部分数据之后,其他document失败了,并不会“回滚”操作,那些成功的document将仍会被保留。isolated在sharded集群中不生效。

 

collection.updateMany(new Document("name", "zhangsan").append("$isolated",1),new Document("$set",new Document("modified", new Date()));

    2、Fields更新:

    1)$inc:对字段的值自增,语法格式:{$inc:{<field1>:amount1,<field2>:amount2}},正负数值都可以,负值表示自减,如果指定的filed不存在,则增加此字段且设定为指定的值。如果字段的值为null,使用inc操作将会抛出错误。

    2)$mul:乘法。

    3)$rename:更改字段的名称,语法:{$rename:{<field1>:<newName1>,<field2>:<newName2>}},新字段不能与原字段名一样,对于内嵌文档,可以使用“.”表示路径。如果文档中已经存在newName,则首先移除那个字段,然后再将指定的Field重命名。如果指定的字段不存在,则什么都不做。

    4)$set:update操作,更新指定字段的值,如果字段不存在则添加此字段和值。

    5)$unset:将指定字段从文档中移除,语法:{$unset:{<field1>:"",....}}。

    6)$min:如果指定的值比字段的当前值要小,那么将字段的值修改为指定的值。比如{$min:{"score":60}},如果文档中score的值 > 60,那么$min将会把score的值修改位60。

    7)$max:语义同$min。

    8)$currentDate:比较有用的指令,将指定字段的值修改为当前时间,类型可以为Date或者Timestamp,默认为Date,语法为:{$currentDate:{<field1>:<type>,....}},需要使用到$type。

    

##使用Date类型,只需要字段值为true即可,当然也可以使用$type:date
##如果是timestamp类型,需要使用$type
{$currentDate:{
    "modified_date":true,
    "modified_timestamp":{$type:"timestamp"}
    }
}

 

    3、Array操作:

    1)$addToSet:将元素添加到指定的数组中,如果数组中已经存在此元素值则不添加。如果此字段不是数组,则操作失败。如果此字段不存在,则创建此字段且将设定为指定的数组元素。语法:{$addToSet:{<field>:<item>}},其中item需要是一个单值,如果是数组,需要借助$each修饰符来拆解。比如:{$addToSet:{<field>:{$each:[item1,item2]}}},此时item1、item2均会分别添加到<field>的数组中。

    2)$pop:从数组的头或者尾部移除一个元素,就像操作双端队列一样。-1表示移除第一个元素,1表示移除最后一个元素。语法:{$pop:{<field>: -1 | 1}}。

    3)$pull:从数据中移除符合条件的所有元素,即有条件的移除。语法:{$pull:{<field1}: <value | condition>,<field2>:<value | condition>....},如果指定的是condition,那么只有某个元素同时满足所有条件才能被删除。比如数组{"item"[{"size":10,"color":"read"},[{"size":30,"color":"black"}]},那么{$pull:{"item":{"size":{$gt:20},"color":"black"}}}将会移除第二个元素。详细参见“pull”。

    4)$push:将元素追加到数组的尾端。语法:{$push:{<field1>:<value1>,<field2>:<value2>,...}},如果需要对一个数组添加多个元素(子数组),那么需要使用$each修饰符。

 

    4、modifiers(修饰符):

    1)$each:可以在$addToSet和$push操作中配合使用,例子参见上。

    2)$slice:我们在read操作中已经了解了slice可以用来限制返回的数组元素个数,那么在write操作中,也可以用过更新后,保留最新的num个元素,它需要配合$push和$each一起使用。

#语法
{
    $push: {
        "field" : {
            $each:[item1,item2,item3],
            $slice:<num>
}

    其中slice的值为0表示将数组置为空,正数表示保留最后num个元素,负数表示保留最前的num个元素。

    3)$sort:同$slice一样,必须配合$push和$each一起使用,表示push之后根据指定的方式对数组进行重排序。1表示正序,-1表示倒序,如果数组元素为内嵌文档,可以使用内嵌文档的字段排序,语法和$slice一样,只是sort部分可以为:$sort: <1 | -1>或者$sort: {<field>: <1 | -1>}

    4)$position:配合$push和$each一起使用,表示push时将元素列表添加到哪个位置,默认为原数组的尾部。$position:0表示添加到第0个元素位置(即首个元素之前)。

 

    5、writeConcern:

    Write connern是mongodb提供了一种保障机制,当write操作成功后可以获得通知。mongodb有多个level的担保,这个有点类似于事务级别。当write操作使用较弱的concern,那么操作可以更快的返回(阻塞更少的时间),但有可能数据并没有持久化(写入磁盘),有丢失的风险;较强的concern需要等待较长的时间但是数据持久能力更强,更不容易丢失。详细请参考“write concern”

    每个write concern包含三个参数:

    1)w选项:默认值为1,即{w:1},即当客户端发送write操作后等待server返回确认信息,write操作只需要在primary上写入成功即可;“0”表示不需要向客户端返回确认信息,即当write操作发送后,客户端不需要等待server的执行结果,但是网络异常这种error仍然可以抛出;“majority”表示当write操作在primary执行成功后,并传播给“大多数”的secondary且执行成功后才返回确认信息,对于replica set架构而言,这种方式是最佳的,可以有效的避免write数据丢失的问题;如果w的值设置成任何>1的值,适合在replica set架构中使用,表示write操作在指定个数的nodes上执行成功后才返回确认信息(包括primary),如果集群中没有足够的nodes在线,则等待足额的节点加入且执行成功后返回。

    2)、j选项

    j选项用来控制mongod实例将数据写入磁盘上的journal日志(注意,是写入磁盘,直接flush),这可以确保在mongod异常关闭后数据不会丢失,如果此选项设置为true,则mongod必须开启journal功能,否则将会报错。当write操作写入journal日志且flush到磁盘后,才向客户端发送确认消息。

    3)、wtimeout选项

    指定write操作的耗时,毫秒,仅当w选项的值 > 1时适用。当write操作超时后,将会返回error,或许此write操作最终成功了(比如primary等待secondary的返回信息,此时超时,则返回给客户端error,不过最终此write可能会在secondary上成功执行,只是还没有来得及向primary返回成功消息),不过mongodb在timeout之后不会撤销已经成功的数据更新。如果设置为0或者没有设置此值,那么write操作将会等待直到满足条件。(可能导致数据不一致)

collection.withWriteConcern(WriteConcern.MAJORITY).updateMany(...)

    

    6、分布式写入操作:

    对于sharded集群中的一个shared collection(即collection允许分片存储),write操作将会由相应的shard节点负责执行,这由config server来决定。参见“分布式写入”。

    对于replica set而言,write操作只能有primary负责接收,并异步的方式传播给secondary,大量的写入操作可能导致secondary不能及时的跟进,那么发生在secondary上的read操作可能会读取到旧的数据,如果primary失效,将会failover其中一个secondary成为primary,为了保证读取一致性也有可能触发rollbacks(即在primary上写入成功,但是在secondary上没有,但是primary失效了,此后primary再次加入,则需要rollback并与secondary保持一致,这也意味着此前的某些write操作丢失)。为了避免这个问题,开发者需要指定合适“write concern”,以确保足够多的secondary能够跟进primary,通过降低write的吞吐量来提高数据一致性(避免网络分区,CAP),此外还需要server端的一些额外的支持,比如oplog、journal等。

 

    7、write操作性能

    如果write操作影响到了索引,那么还需要对相应的索引进行变更。比如insert操作将会导致索引文件中新增条目,update操作中修改了索引的值也会触发索引的调整。所以这也是write操作对性能的影响之一。(高效索引设计有个要求,就是最好不要修改索引的值,是一种低效的操作)

 

    有些update可能会导致document的尺寸增长,对于MMAPV1引擎而言,如果文档大小超过了原来分配的size,那么mongodb将会重新分配一个连续的磁盘空间来保存此文档(废弃以前的文档空间,可以被其他document重用),这也会需要额外消耗一些性能。在mongodb 3.0之后,MMAPV1引擎默认使用了“Power of 2 Size Allocations”以及自动padding,即为每个document分配的size为2的次幂(稍后详解),剩余空间被padding,这可以帮助mongodb高效的重用那些删除文档而产生的空闲空间,以及在很多情况下可以减少了重新分配空间的可能。

    毕竟Mongodb是一个存储系统,高效的磁盘对提升性能有极大的帮助,影响存储性能的因素包括:磁盘介质(SSD,HDD)、磁盘缓存、预读以及RAID配置等。

 

    mongodb通过使用一种称为journal的预写日志来保证write操作的可靠性,在数据写入实际的数据文件之前,首先将变更写入journal(journal日志是append操作,性能较高;但对应实际的数据文件是随机写,性能较低,所以对于数据文件的修改通常是批量 + 延迟写入)。在write concern中开启journal选项,这可以保证write操作的持久性,但是会大大降低整体的write吞吐量。我们可以修改mongod的“commitIntervalMs”,即journal日志flush到磁盘的间隔时间,此值越小,flush的频率越高,持久能力越强,即丢失数据的可能越低,但是对磁盘的IO却越大;此值越大,所来带的问题就是当异常crash时,mongodb丢失数据的风险就越高,因为上次一次flush之后的write尚没有被持久写入journal文件,将可能会丢失。这是一个在性能与可靠性之间的权衡。

 

     8、Bulk write

    mongodb支持批量write操作,即多个write操作批量发送到mongod,同样mongod不会保证这些操作原子性的执行(事务性),只是提高了IO交互的性能。可以将insert、update、remove、replace等多种类型的write批量提交到mongd。

List<WriteModel<Document>> bulks = new ArrayList<WriteModel<Document>>();
bulks.add(new InsertOneModel<Document>(new Document("name","zhangsan")));
bulks.add(new UpdateOneModel<Document>(new Document("name","lisi"),new Document("modified",new Date())));
collection.withWriteConcern(WriteConcern.MAJORITY).bulkWrite(bulks,new BulkWriteOptions().ordered(false));

    Bulk write可以分为ordered或者unordered,通过BulkWriteOptions指定。如果设定了有序性,那么mongod将会依次执行列表中的write操作,如果出错,mongodb将会返回那些尚未执行的操作列表。对于unordered,mongodb则会将它们并行执行,如果出错,也将返回没有执行的操作。由此可见,ordered执行相对较慢,只有其中一个执行成功,才会执行下一个。

 

五、Document

    mongodb中每条document的最大尺寸为16MB,对于超过16MB的数据建议使用Gridfs,一个高效的文件系统。我们稍后再介绍GridFS。

    上文中我们已经提到,Document是BSON结构,key-value对,java中实现为LinkedHashMap,mongodb在保存document时,将尽可能保持字段的顺序;但是_id字段总是在第一个位置,插入时如果没有指定_id则由mongodb生成,有些操作可能会影响字段的顺序,比如$rename。

 

六、其他

    Replica set:复制集,mongodb的架构方式之一 ,通常是三个对等的节点构成一个“复制集”集群,有“primary”和secondary等多中角色(稍后详细介绍),其中primary负责读写请求,secondary可以负责读请求,这有配置决定,其中secondary紧跟primary并应用write操作;如果primay失效,则集群进行“多数派”选举,选举出新的primary,即failover机制,即HA架构。复制集解决了单点故障问题,也是mongodb垂直扩展的最小部署单位,当然sharding cluster中每个shard节点也可以使用Replica set提高数据可用性。

 

    Sharding cluster:分片集群,数据水平扩展的手段之一;replica set这种架构的缺点就是“集群数据容量”受限于单个节点的磁盘大小,如果数据量不断增加,对它进行扩容将时非常苦难的事情,所以我们需要采用Sharding模式来解决这个问题。将整个collection的数据将根据sharding key被sharding到多个mongod节点上,即每个节点持有collection的一部分数据,这个集群持有全部数据,原则上sharding可以支撑数TB的数据。

 

    系统配置:1)建议mongodb部署在linux系统上,较高版本,选择合适的底层文件系统(ext4),开启合适的swap空间  2)无论是MMAPV1或者wiredTiger引擎,较大的内存总能带来直接收益。3)对数据存储文件关闭“atime”(文件每次access都会更改这个时间值,表示文件最近被访问的时间),可以提升文件访问效率。 4)ulimit参数调整,这个在基于网络IO或者磁盘IO操作的应用中,通常都会调整,上调系统允许打开的文件个数(ulimit -n 65535)。

    

MongoDB PHP7 教程 MongoDB 是一个开源的 NoSQL 数据库,使用文档存储数据。与传统的 SQL 数据库不同,MongoDB 使用 JSON-like 文档,这使得数据的存储和查询更加灵活和高效。MongoDB 适用于各种规模的应用,从小的个人项目到大型企业系统。PHP 7 是 PHP 语言的一个重要版本,带来了许多性能和功能上的改进。PHP 7 提供了更快的执行速度、更低的内存消耗和更好的错误处理机制。这些改进使得 PHP 7 成为 Web 开发的首选语言。 阅读详情

相关推荐

MongoDB基本操作

MongoDB是一个基于分布式文件存储 [1]的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

T77589的博客 1771

Java操作MongoDB数据库常用方法介绍

Java操作MongoDB数据库常用方法介绍

记录点点滴滴的成长。 1755

ThingsBoard 3.1.1版本在window本地运行之TB-Gateway服务搭建(三)

TB-gateway服务是TB不可或缺的部分,很多的协议都需要TB-gateway来做分类处理,今天我们就来做TB-Gateway服务搭建。

晚点遇见你,余生都是你! 2474

MongoDB使用游标MongoCursor查询海量数据

1.业务场景 大约70几万条MongoDB数据迁移到mysql 刚开始是先查询总数,然后再根据总数进行分页查询,如果数据量特别大,查询到后面的页会越来越慢,此种情况,可以根据实际情况,对数据进行排序查询后,查询条件加上大于上页最后一条数据的排序键来提升速度。 ```java Date beginTime = DateUtil.parse(startDate + " 00:00:00", DateUtil.PATTERN_DATETIME); Date endTime = DateUtil...

jinbang1991的专栏 5727

配电网故障重构/孤岛划分/故障恢复

程序主要复现《基于GA_BFGS算法的配电网故障恢复性重构研究_郑海广》,采用matlab编程软件实现,依据网络结构和DG供电方式对配电网进行孤岛划分,将含有 DG 的配电网拓扑结构看成一个树,搭建成连通图模型,使得将孤岛的划分变成了求取最小生成树,以网损和开关开断次数作为目标,采用 IEEE33 节点配电网为算例,通过遗传算法寻优计算,从而得到最佳的重构方案。

zhangxd212489的博客 2500

多物理场光学仿真软件:Lumerical_(15).多物理场耦合仿真案例分析

在多物理场光学仿真中,Lumerical 软件提供了强大的工具来模拟复杂的光学系统,包括光子学、热学、力学和电学等多物理场的耦合。本节将通过具体的案例分析,展示如何在 Lumerical 中进行多物理场耦合仿真的开发和实现。我们将从简单的热光效应仿真入手,逐步深入到更复杂的多物理场耦合场景,如光电效应和光力学效应。每个案例都将包括详细的原理说明和具体的代码示例,帮助读者更好地理解和应用这些技术。

kkchenjj的博客 1022

Spring Boot 集成 MongoDB 快速使用入门

目录 Bulk操作 有序操作 无序操作 类文件完整内容 本文承接《MongoDB 通过 Java 代码 CRUD 文档》 Bulk操作 MongoDB提供了一种称为 BulkWrite(块)操作方式,数据不会被立即被持久化到数据库中,而是等待程序调度,确定合适的时间持久化到数据库中,其实就是批量操作。 API :com.mongodb.client.MongoCollect...

蚩尤后裔-汪茂雄 1万+

【大语言模型 85】IA3与其他PEFT方法对比

在大语言模型时代,参数高效微调(PEFT)技术成为了降低微调成本的关键。本文深入解析IA3(Infused Adapter by Inhibiting and Amplifying Inner Activations)方法,并与LoRA、AdaLoRA、Prefix Tuning等主流PEFT技术进行全面对比,通过理论分析、代码实现和实验验证,帮助读者理解不同PEFT方法的优劣势和适用场景,为实际项目中的技术选型提供科学依据。

熵数实验室 753

java mongodb 嵌套数组的更新与处理

最近我们的业务需求有增量更新,虽然后来考虑到复杂性,放弃了对嵌套文档的深嵌套更新,改为删除第一层嵌套再重新入。但嵌套更新的方法还是值得记录下来的。 mongobd 集合的数据格式为 { "_id" : "123", "personCerts" : [ { "perId" : "111", "perName" : "嘿嘿嘿", "certifications" : [...

zwy 3127

Python爬虫实战:如何从Google Maps和OpenStreetMap抓取地理坐标数据

地点名称:地理位置的名称或地址。地理坐标:经度和纬度。类别信息:比如餐馆、商店、公园等。评论数据:如果可用,获取用户评论。本文介绍了如何使用Python爬虫从Google Maps和OpenStreetMap抓取地理坐标数据,并展示了如何存储和分析这些数据。通过实际的代码示例,您可以学习到如何处理不同类型的地图数据抓取任务,以及如何应对反爬虫机制。掌握这些技术后,您可以进行更广泛的地理数据分析,提供更有价值的地理信息服务。

2201_76125261的博客 1039

Qt入门教程【高级控件篇】QModelIndex索引

QModelIndex索引

小鱼酱的博客 4466

MongoDB 批量写操作

MongoDB 批量写(bulkWrite)操作

Mointor 2501

电力系统分析 | Matlab实现源荷场景生成---蒙特卡洛法场景生成启发式同步回带削减

电力系统分析 | Matlab实现源荷场景生成---蒙特卡洛法场景生成启发式同步回带削减

前程算法屋的博客 812

MongoDB(MongoDB安装,基本概述,基本操作,与hive,spark整合)

MongoDB一.MongoDB基本概念1.什么是MongoDB2.MongoDB特点3.MongoDB数据模型4.MongoDB安装(1)配置yum源(2)通过yum进行安装(3)启动(4)MongoDB工具安装二.MongoDB操作1.MongoDB基本命令(1)启动MongoDB(2)查看MongoDB状态(3)查看MongoDB版本(4)启动client Shell命令2.MongoDB的database操作(1)创建(2)删除当前数据库(3)查看所有数据库3.集合操作(1)创建(2)查询(3)删除

May_J_Oldhu的博客 2354

Python爬虫实战:医院科室排班智能采集系统 - 从零构建合规且高效的医疗信息爬虫(附CSV导出 + SQLite持久化存储)!

我长期专注 Python 爬虫工程化实战,主理专栏 👉 《Python爬虫实战》:从采集策略到反爬对抗,从数据清洗到分布式调度,持续输出可复用的方法论与可落地案例。内容主打一个“能跑、能用、能扩展”,让数据价值真正做到——抓得到、洗得净、用得上。

喵手的博客 1298

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

SpringBoot 集成 Spring Data Mongodb 操作 MongoDB 详解

MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,且与关系数据库的最为相像的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。...

weixin_45985053的博客 5474

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

MongoDB的安装及基本操作

MongoDB MongoDB是一个开源文档数据库,提供高性能、高可用性和自动扩展 MongoDB的中的一条记录就是一个文档,是一个数据结构,由字段和值对组成.MongoDB文档与JSON对象类似。字段的值有可能包括其它文档,数组以及文档数组。 使用文档的优势在于: 文档(即对象)对应于许多编程语言中的本机数据类型。 嵌入文档及数组减少了昂贵的加入操作的需求。 动态的设计模式支持流畅的多态。 高性能 MongoDB中提供高性能的数据持久化。 对嵌入式数据模型的支持减少了数据库系统的I / O活动。 索

小颜颜6035的博客 228

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Python —— 操作MongoDB

MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。...

weixin_44451672的博客 577

【MongoDB】(三)MongoDB 基本操作

文章目录一、前言二、MongoDB的特点三、基本操作 一、前言 MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。 在高负载的情况下,添加更多的节点,可以保证服务器性能。 MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。 MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON ...

云祁QI 2772

MongoDB基本操作实验

本实验旨在通过实际操作,掌握MongoDB的基本操作,包括文档的增加、删除、更新,以及使用MongoDB Shell进行交互和查询。一、连接MongoDB Shell。七、使用帮助和Shell命令。二、创建新的数据库和集合。mongo //启动。三、向集合添加新文档。

2201_75467743的博客 558

MongoDB的安装与操作使用

一、MongoDB 1.MongoDB是一个面向文档的基于分布式的NoSQL数据库 存储格式是类似于Json格式(BSON) 2.特点 高性能 易部署 易使用 存储数据非常方便 3.数据模型 单个集合中的文档不必具有相同的字段,集合的不同文档的字段的数据类型可能有所不同 模式验证:可以指定Json模式,插入或更新数据的时候,会按该模式进行验证 上限集合:可以指定MongoDB的集合大小,比如指定1G,当数据达到1G,集合大小不会再增加 二、安装 1.配置yum源 cd /etc/yum.repos.

weixin_49165958的博客 386

MongoDB入门指南:从零开始掌握NoSQL数据库

MongoDB是一种面向文档的NoSQL数据库,使用JSON风格的文档存储数据。它支持动态模式,允许不同文档具有不同的字段结构。MongoDB的设计目标是提供高性能、高可用性和易于扩展的数据库解决方案。MongoDB是一种功能强大且灵活的NoSQL数据库,适合处理非结构化或半结构化的数据。通过本文的介绍,你已经掌握了MongoDB的基本概念、安装方法、操作命令和优化技巧。希望你能够通过实践不断提升自己的技能,并在数据库管理的道路上越走越远。

qq_64012470的博客 4044

mongodb基本操作

文章目录一、mongodb是什么?二、使用步骤1.创建集合2.删除数据3.更改数据4.导入导出5.聚合查询三、总结 一、mongodb是什么? 第一基于分布式存储文件系统,c++编写 介于关系型数据库和非关系型数据之间的一个产品,它本身是一个非关系型数据库,但是又最像非关系型数据库,它具备大量且丰富的查询功能。 可以存储非常复杂的数据类型 二、使用步骤 1.创建集合 注意,key-value之间隔了一个空格,和springboot当中的yaml的配置文件一样的格式。 创建user表 > db.us

qq_41486775的博客 286

MongoDB入门

MongoDB:是一个数据库 ,高性能、无模式、文档性,目前nosql中最热门的数据库,开源产品,基于c++开发。是nosql数据库中功能最丰富,最像关系数据库的。特性l 面向集合文档的存储:适合存储Bson(json的扩展)形式的数据;l 格式自由,数据格式不固定,生产环境下修改结构都可以不影响程序运行;l 强大的查询语句,面向对象的查询语言,基本覆盖sql语言所有能力;l 完整的索引支持,支持查询计划;l 支持复制和自动故障转移;

qq_36037795的博客 1287

MongoDB入门学习以及Spring操作MongoDB

MongoDB入门学习以及Spring操作MongoDB spring-data-mongodb

sinat_38531349的博客 889
上一篇: Mongodb参数限制和阀值
下一篇: Mongodb中Index特性
iteye_19607
博客等级 码龄8年 34粉丝 198原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值