Mongodb Manual阅读笔记:CH2 Mongodb CRUD 操作

时间:2021-11-06 08:46:38

2 Mongodb CRUD 操作

Mongodb Manual阅读笔记:CH2 Mongodb CRUD 操作
Mongodb Manual阅读笔记:CH3 数据模型(Data Models)
Mongodb Manual阅读笔记:CH4 管理
Mongodb Manual阅读笔记:CH5 安全性
Mongodb Manual阅读笔记:CH6 聚合
Mongodb Manual阅读笔记:CH7 索引
Mongodb Manual阅读笔记:CH8 复制集
Mongodb Manual阅读笔记:CH9 Sharding

 

 

mongodb提供了创建,读取,修改,删除简称CRUD

2 Mongodb CRUD 操作... 1

2.1 Mongodb CRUD简介... 2

2.1.1数据库操作... 3

2.1.1.1查询... 3

2.1.1.2数据修改... 3

2.1.2 相关特性... 3

2.1.2.1索引... 3

2.1.2.2读偏好... 3

2.1.2.3写注意(write concern... 3

2.2 Mongodb CRUD概述... 3

2.2.1读操作... 3

2.2.1.1游标... 4

2.2.1.2优化查询... 5

2.2.1.3查询计划... 5

2.2.1.4分布式查询... 5

2.2.2写操作... 5

2.2.2.1写注意(write concern)7

2.2.2.2分布式写... 7

2.2.2.3写操作性能... 7

2.2.2.4存储性能... 7

2.2.2.5大数据量写入... 8

2.2.2.6行留白(Record Padding... 8

2.3 Mongodb CRUD教程... 8

2.3.1 插入文档... 8

2.3.1.1使用insert插入文档... 8

2.3.1.2使用update插入文档... 8

2.3.1.3使用save插入文档... 9

2.3.2查询文档... 9

2.3.2.1 查询全部的文档... 9

2.3.2.2指定条件查询文档... 9

2.3.2.3使用and条件查询... 9

2.3.2.4 使用or条件查询... 9

2.3.2.5使用andor 查询... 10

2.3.2.6子文档... 10

2.3.2.7数组... 10

2.3.3限制查询返回的字段... 11

2.3.3.1 返回所有字段... 11

2.3.3.2返货指定字段和_id. 11

2.3.3.3只返回指定字段... 11

2.3.3.4 返回除某字段外的所有字段... 12

2.3.3.5数组字段的Projection. 12

2.3.4mongo shell中迭代一个游标... 12

2.3.4.1手动迭代游标... 12

2.3.4.2迭代索引... 12

2.3.5分析查询性能... 12

2.3.5.1 评估查询性能... 13

2.3.5.2比较索引性能... 13

2.3.6修改文档... 13

2.3.6.1使用update修改多个文档... 13

2.3.6.2使用save修改文档... 14

2.3.7删除文档... 14

2.3.7.1删除所有文档... 14

2.3.7.2 带条件删除文档... 14

2.3.7.3 带条件删除一个文档... 14

2.3.8 执行二阶段提交... 14

2.3.8.1背景... 14

2.3.8.2模式... 15

2.3.8.3在生产环境使用二阶段提交... 16

2.3.9 创建tailable cursor. 16

2.3.9.1概述... 16

2.3.9.2 C++例子... 17

2.3.10隔离操作顺序... 17

2.3.11创建自增字段... 17

2.3.11.1计数Collection. 17

2.3.11.2 乐观循环... 18

2.3.12 更新数组中限制更新行数... 18

2.3.12.1 方式... 18

2.4 MongoDB CRUD 指南... 19

2.4.1 查询游标方法... 19

2.4.2 查询和数据操作... 19

2.4.3 MongoDB CRUD指南文档... 19

2.4.3.1 写注意(write concern)19

2.4.3.2 sql mongodb的对照表... 20

2.4.3.3 mongodb驱动和客户端lib. 20

 

2.1 Mongodb CRUD简介

mongodb存储的文档是和json格式类似的,但是mongodb存储的是BSON也就是,以2进制方式保存JSON格式数据。在mongodb中文档相当于记录,而存文档的Collection相当于表。

2.1.1数据库操作

2.1.1.1查询

Mongodb可以对一个collection通过条件来过滤文档,并且可以用projection选择输出

2.1.1.2数据修改

创建,更新,删除数据,只能修改单个collection(不包含嵌入方式)

2.1.2 相关特性

2.1.2.1索引

Mongodb可以顺序的表示,也可以强制唯一性保存,mongodb中索引也是用b树保存,

2.1.2.2读偏好

读偏好主要是用在复制集群中,从哪个实例中读取。

2.1.2.3写注意(write concern

不同的写注意保证了不同的数据写入要求,级别越低写入越快,但是写入安全性越低

2.2 Mongodb CRUD概述

读操作:游标,查询优化,分布式查询

写操作:写注意,分布式写操作

2.2.1读操作

查询接口

         Mongodb通过提供的接口db.collection.find()方法来查询数据,会返回一个游标

查询行为

         1.所有的查询只能针对一个collection

         2.可以通过limitsskipssort来影响查询结果

         3.sort()来范围查询的顺序

         4.update修改数据和select的条件语法一样

         5.aggregation(聚合)管道中,$match管道提供了对mongodb的访问

查询语句

Mongodb Manual阅读笔记:CH2 Mongodb CRUD 操作

Projection

         Projection用来限制输出那些字段,_id是默认输出的。

         Projection行为

                   1._id会默认出现,除非显示设置

                   2.对于包含array的字段,提供了$elemMatch,$slice,$等操作符

                   3.对于聚合,使用$Project来处理

2.2.1.1游标

         mongodb查询db.collection.find()返回一个游标,若没有分配给一个变量直接运行20

         游标行为对于游标默认不活动时间超过10分钟就会被销毁,当然可以指定noTimeout标记,来先限制等待。

         游标隔离级别游标在有效期内是不隔离的,若有写入操作就会影响,可以使用快照模式来处理

         游标Batch数据从mongodb到客户端是以batch的方式,batch的大小最大不超过最大BSON文档的大小,对于很多查询而言,第一个batch返回101个文档,或者1MB的大小,之后是4MB

         对于包含sort的查询但是没有索引,mongodb会导入到内存然后排序,会在第一个batch的时候返回所有的结果。用cursor.hasnext()cursor.next()的组合来看有没有下一个batct,获取下一个batch

         游标信息通过命令cursorInfo来获取游标的信息:1.打开的游标总数,2.当前使用的客户端游标大小,3.从服务重启来,超时的游标数。

2.2.1.2优化查询

         索引和其他数据库中的一样,减少了没必要数据的查询。

         创建索引来支持查询使用db.collection.ensureIndex()来创建索引

         索引的选择度某些查询操作时选择度很差,比如$nin,$ne,高选择度的才可以更好的使用索引,$regex      也是没有办法使用索引的。

         覆盖查询覆盖查询的条件:1.所有的字段都是索引的一部分,2.所有返回的字段也在索引中

2.2.1.3查询计划

Mongodb优化器处理查询,并根据索引选择一个最有效的索引,当collection的数据量被改变优化器会偶尔重建计划,可以使用explain()来查看执行计划。

         查询优化

优化器创建计划的过程:1.通过不同的索引,并发的执行查询,2.记录负荷的结果到buffer中,3.当非排序的查询计划全部返回,或者顺序的执行计划全部返回,或者顺序的执行计划返回了超过了一个指标,那么会停止其他执行的计划并选择这个计划

         计划重建

当发生以下事件,计划会被重建:1.超过1000个写入,2.重建索引,3.添加或者删除索引,4.服务进程重启

2.2.1.4分布式查询

         Sharded集群中读Sharded允许数据分区,并对应用程序透明,查询会通过路由到达相关的实例中,通过shard key若没有shard key,查询会分发到索引的shard实例中取执行。

         从复制集群中读,在复制集群中使用读偏好,来决定从哪个实例中读取数据,读偏好设置有一下几个好处:1.减少延迟,2.提供读的带宽,3.备份作用,4.容灾切换。同时也要注意,主库和分库之间的延迟,分库不能代表当前主库的数据状态。

2.2.2写操作

和读一样写操作只能用在一个collection上。

创建

         通过接口,db.collection.insert()collection上创建一个文档,若update接口在有upset的标记下,也可以实现创建文档的功能。

Mongodb Manual阅读笔记:CH2 Mongodb CRUD 操作

插入的行为

         如果你插入时,没有指定_id那么mongodb会分配一个,若指定了_id需要保持在collection中是唯一的。

更新

         通过接口,db.collection.update()来实现更新操作,也可以用save

  Mongodb Manual阅读笔记:CH2 Mongodb CRUD 操作

更新行为

         update默认只对一行进行更新,若要对多行进行更新要使用multi选项,通没有指定类似set的参数,就会把所有影响的文档替换,当更新是,文档的大小超过了原先分配的大小,那么会重新分配空间,然后把文档放入,这样会导致,文档内的字段重排。

删除

         删除通过接口,db.collection.delete()实现。

Mongodb Manual阅读笔记:CH2 Mongodb CRUD 操作

删除的行为

         默认使用delete不太条件,会把所以的文档全部删除

写操作的隔离性

         修改一个文档,可以支持原子性,但是对多个文档的修改就不支持原子性,尽管如此单还是可以使用隔离操作(isolaation_operator)。也可以通过人工方式实现2阶段提交,来保证隔离性。

2.2.2.1写注意(write concern)

         弱写注意,可能会导致一些错误,因为不需要等服务端返回写入成功,强写注意,client可以等待写入完成。db.runCommand( { getLastError: 1, w: 2 } )来配置。

 

         写注意级别:忽略错误(Error Ingored),最低级的级别,mongodb不会通知写入操作完成,包含        发生错误,性能最佳,但是会影响写入数据的一致性和持久性,w:-1

         不通知mongodb不会通知写入成功或者失败,但是当发生错误是,还是会尽力接受和处理错误,可以发现由系统网络配置导致的网络错误。w:0

         通知:可以取回一个写入操作信息,这个级别,允许客户端抓取网络,重复key等错误,w:1mongodb默认使用这个级别,写注意默认使用无参数的getLastError,对于复制集群可以在getLastErrorDefaults中定义默认的写注意,若没有定义默认使用getLastError取通知.

         日志:使用这个级别,只有在提交,写入日志后,服务才会通知写入操作,这样可以保证服务崩溃后数据库的恢复。使用这个操作要指定w:1,j:true

         复制通知:使用这个级别可以保证,写操作写入到了复制集群,w:>1,在复制集群下,只要再设置j:true,主库就可以用日志写注意级别。

2.2.2.2分布式写

         sharded集群中写:可以根据shard key来对分区插入数据,可以提高写入性能,若没有key,会被广播到所有的shard,若数据库只插入到一个key,那么可能照成单点性能问题。

         在复制集中写:在复制集中写入,会被写入到primary上,然后记录在oplog或者log中,然后根据oplog分发到分库中,对于密集的写入操作会导致分库和主库之间严重的延迟,虽然可以通过写注意保证一致性,但是会造成写入性能问题

2.2.2.3写操作性能

         索引:和其他数据库一样,写操作会修改索引,会带来一些性能消耗。

         文档增长update 操作文档的空间时,会分配一个新空间,然后把文档复制进去,这样会加大update的时间,in-place比文档增长来的有效。

2.2.2.4存储性能

         硬件:很多元素和存储系统有关,影响着服务的性能,如,随机读写性能,磁盘cache,预读,RAID级别。

         日志mongodb使用顺序写方式来记录日志,日志提供了一致性和crash弹性,考虑一下方面来增加日志性能:1.使用独立的设备,2.若写注意级别为日志,mongodb通过减少提交间隔来减少写负荷,3.通过手动配置journalCommitInterval来减少提交间隔。

2.2.2.5大数据量写入

         使用insert方法insert方法通过传入一个数组来执行大数据量写入。通过写注意的设置大数据量写入,可以显著的提高性能。并且通过ContinueOnError选项可以让批量插入有错误下还能完成。

         Shard集群中ContinueOnError只在非分片中有效,这类大批量写入,对sharded集群来说会降低性能若要写入考虑一下方案:

                  预分配splits:大批量导入中,若collection是空的,那么只有一个spilt,当插入时    重新分配split导致性能问题所以要预先split

                   避免单调增长:可能大批量插入只针对一个sharded key,这样sharded的性能就没        有办法体现,如无法避免,可以考虑:1.二进制方式翻转shard key2.key的前16位和  16位互换。

2.2.2.6行留白(Record Padding

         因为超出文档就会重新分配,为了避免这个问题,可以事先留白,减少重分配的可能性。

         留白因子:可以使用db.collection.stats()查看当前的paddingFactor,留白的大小可以通过一个公式计算:padding size = (paddingfactor-1)*<document size>。留白并不能对每个文档做准确的设置,只能根据文档大小的平均数。留白的大小只能通过执行compact或者repairDatabase选项回收。

         删除留白:可以通过compactrepairDatabase和初始化复制同步选项来移除,导出导入也可以。

         行分配策略:为了更加有效的使用因为删除而空闲的空间,或者文档重新分配的空间,可以指定mongodb分配的行大小,大小为2n次。

2.3 Mongodb CRUD教程

2.3.1 插入文档

mongodb中,可以使用insertupdatesave来插入数据

2.3.1.1使用insert插入文档

inventory插入数据:db.inventory.insert( { _id: 10, type: "misc", item: "card", qty: 15 } )

2.3.1.2使用update插入文档

使用update插入文档的时候要指明upserttrue,表示如果有数据则修改,没数据则插入

db.inventory.update(

{ type: "book", item : "journal" },

{ $set : { qty: 10 } },

{ upsert : true }

)

{ "_id" : ObjectId("51e8636953dbe31d5f34a38a"), "item" : "journal", "qty" : 10, "type" : "book" }

插入的文档如果没有指定_id mongodb会自动分配一个_id

2.3.1.3使用save插入文档

inventory插入数据db.inventory.save( { type: "book", item: "notebook", qty: 40 } )

{ "_id" : ObjectId("51e866e48737f72b32ae4fbc"), "type" : "book", "item" : "notebook", "qty" : 40 }

2.3.2查询文档

mongodb中,find()返回一个游标,通过游标来获取返回的文档。

2.3.2.1 查询全部的文档

可以使用如下来查询所有的文档:

db.inventory.find( {} )db.inventory.find()

2.3.2.2指定条件查询文档

如果要在inventory中查询typefood或者snacks的:

db.inventory.find( { type: { $in: [ 'food', 'snacks' ] } } )

2.3.2.3使用and条件查询

mongodb中,只要都好分开就表示and条件

db.inventory.find( { type: 'food', price: { $lt: 9.95 } } )

2.3.2.4 使用or条件查询

db.inventory.find(

{ $or: [

{ qty: { $gt: 100 } },

{ price: { $lt: 9.95 } }

]

}

)

2.3.2.5使用andor 查询

db.inventory.find( { type: 'food', $or: [ { qty: { $gt: 100 } },

{ price: { $lt: 9.95 } } ]

} )

2.3.2.6子文档

当要查询子文档的时候,可以指定子文档的所有值,也可以使用.(点号) 获取子文档的字段值。

精确的匹配文档

也就是匹配整个子文档

db.inventory.find(

{

producer: {

company: 'ABC123',

address: '123 Street'

}

}

)

使用子文档的字段匹配

用点号获取子文档的值

db.inventory.find( { 'producer.company': 'ABC123' } )

2.3.2.7数组

匹配方式和子文档类似

匹配整个数组

db.inventory.find( { tags: [ 'fruit', 'food', 'citrus' ] } )

匹配某个元素

只要某个元素在数组中都会被匹配

db.inventory.find( { tags: 'fruit' } )

匹配指定元素

db.inventory.find( { 'tags.0' : 'fruit' } )

子文档数组

使用数组所有匹配子文档中的字段:db.inventory.find( { 'memos.0.by': 'shipping' } )

多字段匹配

db.inventory.find(

{

'memos.memo': 'on time',

'memos.by': 'shipping'

}

)

2.3.3限制查询返回的字段

Projection可以限制字段的输出

2.3.3.1 返回所有字段

Find,函数第二个参数就是projection如果不填就是全部返回

2.3.3.2返货指定字段和_id

db.inventory.find( { type: 'food' }, { item: 1, qty: 1 } )

其中_id字段是默认返回的所有不用指定

2.3.3.3只返回指定字段

db.inventory.find( { type: 'food' }, { item: 1, qty: 1, _id:0 } )

因为_id是默认返回的,所以要设置_id不返回。

2.3.3.4 返回除某字段外的所有字段

db.inventory.find( { type: 'food' }, { type:0 } )

2.3.3.5数组字段的Projection

对于数组来说唯一可用的projection操作就是$elemMath$slice

2.3.4mongo shell中迭代一个游标

find函数没有赋值给变量,在shell中会直接迭代20次。

2.3.4.1手动迭代游标

通过以下方式可以直接迭代20

var myCursor = db.inventory.find( { type: 'food' } );

myCursor

也可以手动迭代

var myCursor = db.inventory.find( { type: 'food' } );

var myDocument = myCursor.hasNext() ? myCursor.next() : null;

if (myDocument) {

var myItem = myDocument.item;

print(tojson(myItem));

}

还可以用forEach方法

var myCursor = db.inventory.find( { type: 'food' } );

myCursor.forEach(printjson);

2.3.4.2迭代索引

mongo shell中可以可以直接把游标toArray(),然后直接访问数组即可。

var myCursor = db.inventory.find( { type: 'food' } );

var documentArray = myCursor.toArray();

var myDocument = documentArray[3];

2.3.5分析查询性能

Explain()游标方法,这个方法用来分析查询的效率,确定如何使用索引。

2.3.5.1 评估查询性能

db.inventory.find( { type: 'food' } ).explain()

结果

{

"cursor" : "BtreeCursor type_1",

"isMultiKey" : false,

"n" : 5,

"nscannedObjects" : 5,

"nscanned" : 5,

"nscannedObjectsAllPlans" : 5,

"nscannedAllPlans" : 5,

"scanAndOrder" : false,

"indexOnly" : false,

"nYields" : 0,

"nChunkSkips" : 0,

"millis" : 0,

"indexBounds" : { "type" : [

[ "food",

"food" ]

] },

"server" : "mongodbo0.example.net:27017"

}

Cursor的值为btreecursor表示是用了索引

n表示返回的文档数

2.3.5.2比较索引性能

如果要比较索引之间的性能可以使用hint来强制

db.inventory.find( { type: 'food' } ).hint( { type: 1 } ).explain()

db.inventory.find( { type: 'food' } ).hint( { type: 1, name: 1 } ).explain()

2.3.6修改文档

修改文档的操作有,update saveupdate是修改文档,save如果文档存在则替换文档。

2.3.6.1使用update修改多个文档

要修改多个文档时,要把multi-true设置上。

db.inventory.update(

{ type : "book" },

{ $inc : { qty : -1 } },

{ multi: true }

)

2.3.6.2使用save修改文档

Save可以替换已经存在的文档

db.inventory.save(

{

_id: 10,

type: "misc",

item: "placard"

}

)

2.3.7删除文档

删除文档一般使用remove方法

2.3.7.1删除所有文档

直接写不带参数的remove就会把collection中的文档全部删除。

db.inventory.remove()

2.3.7.2 带条件删除文档

db.inventory.remove( { type : "food" } )

2.3.7.3 带条件删除一个文档

db.inventory.remove( { type : "food" }, 1 )

2.3.8 执行二阶段提交

当处理多文档的更新和事务,可以使用二阶段提交的方式来写多个文档

2.3.8.1背景

单文档操作是原子的,多文档没有,所以多文档的操作不能有原子性保障,当执行事务时就可能发生以下问题:

1.原子性:如果一个操作失败,事务必须回滚到之前的状态

2.隔离性:同步发生的事务,在事务过程中必须看到一致性的数据

3.一致性:如果发生数据库错误,中断了事务,数据库必须能够恢复到一致的状态

多文档的写可以使用二阶段提交

2.3.8.2模式

概述

假设要做转账操作,我们有一个accounts collection和一个transactions collection用来保存用户数据和事务数据。

db.accounts.save({name: "A", balance: 1000, pendingTransactions: []})

db.accounts.save({name: "B", balance: 1000, pendingTransactions: []})

事务描述

设置事务初始化状态:在创建的 transactions中插入一条数据并且状态为initial

db.transactions.save({source: "A", destination: "B", value: 100, state: "initial"})

然后把事务状态设置为pending:在要处理事务之前把事务状态设置为pending表示处理这个事务。db.transactions.update({_id: t._id}, {$set: {state: "pending"}})

应用事务到2个账号上

db.accounts.update({name: t.source, pendingTransactions: {$ne: t._id}}, {$inc: {balance: -t.value}, $push: {pendingTransactions: t._id}})

db.accounts.update({name: t.destination, pendingTransactions: {$ne: t._id}}, {$inc: {balance: t.value}, $push: {pendingTransactions: t._id}})

更新accountpendingTransaction中没有t._id的事务,就是t._id不是已经在处理事务,然后设置值,并把设置上pendingTransaction

设置事务提交状态db.transactions.update({_id: t._id}, {$set: {state: "committed"}})

删除pending事务

db.accounts.update({name: t.source}, {$pull: {pendingTransactions: t._id}})

db.accounts.update({name: t.destination}, {$pull: {pendingTransactions: t._id}})

设置事务完成

db.transactions.update({_id: t._id}, {$set: {state: "done"}})

从错误场景中恢复

可能会出现错误的场景:

1.在初始化事务,应用事务到2个账号上之间出错,为了恢复应用程序应该获取pending状态的事务,然后继续处理。

2.发生在应用事务,事务完成之间的错误,为了恢复应用程序应该获取done状态的事务,然后继续处理。

回滚:某些场景就需要回滚操作

1.当应用事务之后,已经提交了事务,就不应该去回滚事务,而是重新创建一个新的事务,来交换数据

2.在创建事务后,但是没有应用事务,可以使用一下步骤:

设置事务状态为取消db.transactions.update({_id: t._id}, {$set: {state: "canceling"}})

Undo事务

db.accounts.update({name: t.source, pendingTransactions: t._id}, {$inc: {balance: t.value}, $pull: {pendingTransactions: t._id}})

db.accounts.update({name: t.destination, pendingTransactions: t._id}, {$inc: {balance: -t.value}, $pull: {pendingTransactions: t._id}})

把事务状态修改为已取消db.transactions.update({_id: t._id}, {$set: {state: "canceled"}})

多应用程序:多应用程序的时候很容易造成一致性问题和冲突。在这种情况下,在transaction中加入application字段,来区别应用程序。并且使用findAndModify()

t = db.transactions.findAndModify({query: {state: "initial", application: {$exists: 0}},

update: {$set: {state: "pending", application: "A1"}},

new: true})

2.3.8.3在生产环境使用二阶段提交

在例子中,我们假设了一些东西比如:

1.总是可以回滚一个用户

2.账号的剩余可以为负数

但是在生产环境下需要考虑:

1.在把事务设置为pending的时候,需要查看账号是否有足够的资金。

2.当事务设置提交时,需要修改借贷方

当然这些操作时在一个文档里面的,是原子的

也需要考虑:

1.数据库接口的写注意(wirte concern)

2.mongodjournaling是否开启确保数据库非干净关闭后数据库状态的恢复。

2.3.9 创建tailable cursor

2.3.9.1概述

默认游标使用完之后就会被关闭,但是Tailable Cursor不会,当文档有插入,Tailable Cursor也可以取到。对于高写入的capped collection上使用tailable cursor太昂贵。

Tailable cursor有一下特点:

1.游标不会使用索引,以自然顺序返回

2.tailable cursor在初始化阶段比较昂贵,新增的文档代价并不是很大。

3.某些情况下tailable curos会不可用,没有返回的文档,返回了collection的末尾,然后被应用程序删掉了。

2.3.9.2 C++例子

看手册p75

2.3.10隔离操作顺序

看手册p76

2.3.11创建自增字段

本节介绍2个创建自增的方法,计数collection,乐观循环(optimistic loop

2.3.11.1计数Collection

使用一个独立的计数Collection来跟踪最新的顺序,_id表示顺序的名,seq表示最新的顺序。

1.插入一个userid的初始化值到计数collection

db.counters.insert(

{

_id: "userid",

seq: 0

}

)

2.创建一个getNextSequence函数来获取一个名字的下一个顺序值。

function getNextSequence(name) {

var ret = db.counters.findAndModify(

{

query: { _id: name },

update: { $inc: { seq: 1 } },

new: true

}

);

return ret.seq;

}

3.在插入时使用getNextSequence函数

db.users.insert(

{

_id: getNextSequence("userid"),

name: "Sarah C."

}

)

2.3.11.2 乐观循环

读者觉得很奇葩的方法,手册 p80

2.3.12 更新数组中限制更新行数

2.3.12.1 方式

students collection有一个文档

{

_id: 1,

scores: [

{ attempt: 1, score: 10 },

{ attempt: 2 , score:8 }

]

}

然后再$push里面使用$each$sort来实现

db.students.update(

{ _id: 1 },

{ $push: { scores: { $each : [

{ attempt: 3, score: 7 },

{ attempt: 4, score: 4 }

],

$sort: { score: 1 },

$slice: -3

}

}

}

)

输出结果

{

"_id" : 1,

"scores" : [

{ "attempt" : 3, "score" : 7 },

{ "attempt" : 2, "score" : 8 },

{ "attempt" : 1, "score" : 10 }

]

}

2.4 MongoDB CRUD 指南

2.4.1 查询游标方法

Cursor.count:返回文档的个数

Cursor.explain:显示查询的执行计划

Cursor.hint:强制mongo使用指定的索引

Cursor.limit:显示游标返回文档个数

Cursor.next:获取游标中下一个文档

Cursor.skip:跳过给定数量的文档

Cursor.sort:对指定字段排序

Cursor.toArray:游标返回成数组

2.4.2 查询和数据操作

Db.collection.count:返回collection文档个数

Db.collection.distinct:以数组方式返回指定字段的不同值

Db.collection.find:在collection执行find返回游标

Db.collection.findOne:返回一个文档

Db.collection.insert:在collection上创建文档

Db.collection.remove:删除collection上的文档

Db.collection.save:可以insert,也可以替换已经存在的文档

Db.collection.update:修改已经存在的文档

2.4.3 MongoDB CRUD指南文档

主要介绍,写注意(write concern),sql mongodb的对照表,mongodb的驱动和客户端lib

2.4.3.1 写注意(write concern)

概述

Write concernmongodb为写入提供的保障,但是是通过消耗性能来保证write的安全性。可以对数据的重要性不同分级。

可以用的write concern

提供write concern,写入操作之后,驱动使用getLastError来获取最后才做的信息。返回一个err字段,:

1.null表示写入成功

2.null就表示具体的错误

GetLastErroe的参数:

J或者journal选项:指定这个选项后,mongodb会写入日志到磁盘的journal上确保mongodb突然关闭之后数据不会丢失。

如下:db.runCommand( { getLastError: 1, j: "true" } )

如果在mongod中并没有启用journal,然后getLastError指定了 j:true会返回一个jnote字段包含了这个文档。

W选项:这个选项可以停用write concern,也可以指定复制集的write concern。可选值:

-1:关闭write operation通知

0:关闭基本的写入操作通知,但是返回socket异常和网络异常

1:提供通知,说明已经写入到了单个实例,或者复制集的primary

>1:说明要写入到>1个实例中。一般用户复制集,如果这个值大于复制集成员,mongodb会一致等下去。

Majority:确认写入操作已经传播到大多数的已配置复制集

Tag设置:使用tag设置可以很好的控制复制集成员很好的控制的不同write concern

getLastError还提供了一个超时,如果给0会一直等待。

2.4.3.2 sql mongodb的对照表

手册p85

2.4.3.3 mongodb驱动和客户端lib

手册p95