mongodb学习总结

安装mongodb:

1.下载服务器最新稳定版本(选择偶数号的版本号),mongodb的版本管理偶数号为稳定版,奇数号为开发版。

2.安装时默认安装在c盘,可以选择自定义选项来改变安装路径。

3.安装完成后必须手动在安装路径的根路径下创建一个data\db文件夹,如果你的mongodb安装在d盘,那db文件夹的路径就是d:\data\db,否则启动mongod.exe时会因为数据目录文件夹找不到而无法启动。

 

运行mongodb:

打开cmd 命令行工具 cd 到 mongodb二进制(bin)目录下,然后执行mongod.exe(可省略后缀)即可开启mongodb服务。

如果想改变mongodb默认的数据目录(mongodb安装所在根目录下的data\db)路径,可以使用--dbpath参数来手动指定db文件夹路径

使用--help选项可以查看mongod.exe支持的所有选项。

 

作为一个windows服务(service)安装:

只需以全路径运行mongod.exe命令并指定--install选项即可安装完成,之后就可以在windows服务面板中启动和停止了。

例:D:\MongoDB\Server\3.6\bin\mongod.exe --dbpath F:data\db --install注:书中--dbpath这里加了"\"dbpath\""来包裹路径,不明白什么原因,如果上面例子无效,可尝试使用"\"包裹路径

 

运行后mongod默认监听27017端口。另外书中说mongod还会启动一个非常基本的http服务器,监听的端口是28017,不过貌似最新版本已经废弃这个功能,它的替代方案应该是compass,经测试我用的3.6版本中已经不存在这个http端口了,也就无法通过localhost:28017访问数据库的管理信息了。启动中按下ctrl+c来停止mongod服务

 

使用命令行mongodb shell与mongodb实例交互:

mongodb shell非常有用,通过它可以执行管理操作,检查运行实例,亦或做其他尝试。

mongodb shell包含一个功能完备的javascript解释器,可以运行任意的javascript程序。

1.运行shell

同样的要先cd到mongodb bin目录下,然后执行mongo.exe程序,注意mongo不带参数时默认会自动连接到本地的mongodb实例,所以需确保本地实例服务已启动。

启动时可以指定主机和端口号来连接到其他实例,例如:mongo.exe 210.138.20.165:3000/dbname。

也可以启动时不去连接任何的实例之后再手动连接,使用--nodb参数即可,启动之后执行new Mongo(hostname)语句就可以连接到目标实例了,示例:conn= new Mongo("210.138.20.165:3000");db= conn.getDB("dbname"),执行完这些语句之后就可以像平常一样使用db变量了,这里没有使用变量声明关键字,表示变量范围是全局的。

shell启动后可以输入任意javascript代码,按下回车可查看代码执行结果。注意:shell会检测输入的js语句是否完整,如没写完可在下一行接着写,在输入不完整的某行上连续三次回车可取消输入,并回到shell命令提示符(> )。

2.mongodb shell是一个独立的mongodb客户端

默认情况下shell启动时会连接到test数据库,并将数据库连接赋值给全局变量db,这个变量是访问mongodb的主要入口点。

使用help命令来查看帮助文档。

如果想知道一个函数的实现代码,可以直接在命令行输入函数名(后面不跟括号),这样就可以知道函数的工作机制,以及使用方式。

另外shell还可以执行.js文件脚本,具体用法不再赘述,请参考书中2.7.2内容。

1.使用use [db name]命令(这个命令是为熟悉sql shell的用户提供的语法糖)来切换数据库

2.命令行输入db来查看当前连接的数据库名

3.可以使用db.[collection name]来访问集和

4.基本操作:

4.1.插入文档:

db.[collection name].insert(doc);doc是一个js json对象,例如:var doc= {"name":"gao","age":25}。注意:插入文档时如果指定的集和或当前数据库不存在将被创建。

如果insert文档时没有指定"_id"键的话,insert操作会自动给文档增加一个"_id"键,然后保存到mongodb中。

批量插入:

如果要想集合插入多个文档可以使用batchInsert函数来实现,它接收一个json文档数组作为参数,例子:db.coll.batchInsert([{"name":"a"},{"name":"b"}]);,它比一个一个的用insert函数去插入速度快的多,文档数量越多越明显。

注意单次插入文档请求时貌似不能同时插入到多个集合内,并且单次插入请求的最大的消息长度不能超过48m,不过大多数mongodb数据库客户端驱动程序会将超过48m的请求拆分为多个48m去执行。

如果批量插入过程中有一条文档插入失败,那么在这个文档之前的所有文档都会成功插入,而这个文档以及之后的都会插入失败。如果希望忽略错误并继续执行后续插入,可以使用continueOnError选项,shell并不支持这个选项,但是所有驱动程序都支持。

插入数据时,mongodb会对数据进行最基本的检查,其中一项就是文档必须小于16m,可以使用Object.bsonsize(doc)函数来查看文档大小。

顺便说一下bson和mongodb文档的关系:mongodb的文档是一个抽象概念,而文档的具体存在方式就是bson(binary json,二进制json),bson是一种轻量的二进制格式,可用一串字节来描述mongodb文档,数据库能够理解bson格式,bson也是文档存放于磁盘中的格式。bson可以理解为json的升级版

4.2.查看文档:

db.[collection name].find();查看集和内的文档,find默认情况下最多返回20条文档。若只想查看一个文档可使用db.[collection name].findOne();findOne只会返回1条文档结果,不管有匹配到几条文档,仅返回第一条。find和findOne方法可以接受一个文档对象(json)作为查询限制条件。

查询时支持使用正则表达式作为限定条件,语法与js正则相同,例如:db.collection.find({"name":/gao/i}),文档内也支持存储正则表达式类型数据,但暂时想不到使用的场景。

 

find:mongodb中使用find进行查询,查询就是返回一个集合中文档的子集,子集的范围是从0个文档到整个文档。find的第一个参数决定了要返回哪些文档,这个参数是一个文档,用于指定查询条件。空的查询文档(例如{})会匹配集合的全部内容,要是不指定查询文档参数,默认就是{}。

查询文档参数:可以向查询文档中加入多个键/值对,将多个查询条件组合在一起,这样的查询条件会被解释成"条件1 and 条件2 and .. 条件n"

指定需要返回的键:有时并不需要将文档中的所有键/值对都返回。这时可以通过find(或者findOne)的第二个参数来指定要返回的键,举例:db.blog.find({},{"name":1});默认情况下"_id"这个键总是被返回,即便没有指定这个键要返回,但可以指定{"_id":0}来剔除掉,即1是包含0是剔除。

查询条件:

$lt,$lte,$gt,$gte就是全部的比较操作符,分别对应<,<=,>,>=,查询年龄大于18小于30的用户:db.user.find({"age":{"$gte":18,"$lte":30}});,这样的范围查询对日期尤其有用。$ne表示不相等,它可以用于所有类型的数据。

or查询:

$in:可以用来查询一个键的多个值。一个键需要多个值进行匹配的话,就要用$in操作符,再加一个条件数组,例如:查询name等于"a"或"b"或"c"的用户,db.user.find({"name":{"$in":["a","b","c"]}});,$in非常灵活可以指定不同类型的条件和值。如果$in对应的数组只有一个值,那么和直接匹配这个值效果一样。与$in相对的是"$nin",$nin将返回与数组中所有条件都不匹配的文档。

$or:更通用一些,可以在多个键中查询任意的给定值。$or接受一个包含所有可能条件的数组作为参数。举例:要查询性别男或者18岁以上的用户,db.user.find({"$or":[{"sex":"男"},{"$gt":{"age":18}}]});

$not:是元条件句(书上这么翻译的),即可以用在任何其他条件之上。用于取反,与正则表达式联合使用时极为有用,用来查找那些与特定模式不匹配的文档。

$mod:取模运算符,会将查询的值除以第一个给定值,若余数等于第二个给定值则匹配成功,例子:db.user.find({"age":{"$mod":[2,1]}});//表示年龄除以2的余数等于1的用户将会被匹配。

条件语句是内层文档的键,而修改器则是外层文档的键。有一些"元操作符"也位于外层文档中,比如"$and","$or"和"$not",注意查询优化器不会对"$and"进行优化,这与其它操作符不同(意思是其它操作符会被优化),不显式的使用时效率更高(默认即and)。一个键可以有任意多个条件,但是一个键不能对应多个更新修改器(见4.2.4章节 条件语义)。

特定类型的查询:

null:不仅会匹配某个键为null的文档,而且还会匹配不包含这个键的文档。如果仅想匹配值为null的文档,既要检查改键 的值是否为null,还要通过$exists条件判定键值已存在。db.user.find({"z":{"$in":[null],"$exists":true}});//很遗憾没有$eq操作符,看起来这条查询语句有些令人费解,但是效果只有一个元素的$in操作符是一样的。

正则表达式:正则表达式能够灵活有效的匹配字符串。例子:db.user.find({"name":/gao/i});//匹配所有名为不区分大小写的gao的用户。mongodb使用perl兼容的正则表达式库(PCRE)来匹配正则表达式,任何PCRE支持的正则表达式语法都能被Mongodb接受。正则表达式也可以匹配自身,虽然几乎没有人直接将正则表达式插入到数据库中,但要是万一你这么做了,也可以匹配到自身。

数组查询:查询数组元素与查询 标量(非数组元素)值是一样的。例如文档:{"arr":[1,2,3]},那么db.test.find({"arr":2});就可以匹配到这条文档。如果需要通过多个元素来匹配数组,就要用$all操作符了,例子:db.test.find({"arr":{"$all":[2,3]}});//这里$all的元素顺序无关紧要,只要数组包含这两个元素即匹配。要是对只有一个元素的数组使用$all,就和不用$all一样了。也可以使用整个数组进行精确匹配,但是精确匹配对其缺少元素或者元素冗余的情况就不大灵了,例如:db.test.find({"arr":[2,3]});//它只会匹配到arr数组只有2和3的文档。要想查询数组特定位置的元素,需使用key.index语法指定下标,例如:db.test.find({"arr.1":2});//查询arr第二个元素的值等于2的文档,注意数组下标都是从0开始的。

$size:用于查询特定长度的数组。如:db.test.find({"arr":{"$size":2}});$size并不能与其他查询条件(比如$gt)组合使用(解决方案见4.3.3的2章节)。

$slice:可以返回某个键匹配的数组元素的一个子集。比如:返回博客文章的前10条评论,db.blog.find(criteria,{"comments":{"$slice":10}});,也可以指定偏移值以及希望返回的元素数量,比如:db.blog.find(criteria,{"comments":{"$slice":[10,5]}});,这个操作会跳过前10个元素,返回第11~15个元素,如果数组不够15个元素,返回10个元素后面的所有元素。除非特别声明,否则使用$slice时将返回文档中的所有键,别的键说明符都是默认不返回未提及的键,这点与$slice不太一样。

返回一个匹配的数组元素:有时我们希望返回与查询条件相匹配的任意一个数组元素,可以使用$操作符得到一个匹配的元素。例如:db.blog.find({"comments.name":"bob"},{"comments.$":1});//注意:这样只会返回第一个匹配的文档,如果bob在这篇文章写过多条评论,只有comments数组的第一条评论会被返回。

数组和范围查询的相互作用:文档中的标量(非数组元素)必须与查询条件中的每一条语句相匹配,但是如果匹配的字段是一个数组,数组的某一个元素与查询条件的任意一条相匹配(查询条件中的每条语句可以匹配不同的数组元素,举个例子:如果匹配条件=x字段大于1并且小于3,并且x字段是个数组,它的下标0的元素=3,下标1的元素=2,那么就会满足这个匹配条件,因为下标0的3满足了大于1,下标1的2满足了小于3),那么这个文档也会被返回。

$elemMatch:要求mongogdb同时使用查询条件中的多个语句与一个数组元素进行比较,但是$elemMatch不会匹配非数组元素。db.test.find({"x":{"$elemMatch":{"$gt":10,"$lt":20}}});//这样就可以解决上面那种情况了

min、max:如果当前查询的字段上创建过索引,可以使用min和max函数将查询条件遍历的索引范围限制为"$gt"和"$lt"的值。关于min、max可能需要了解过索引之后才能明白,可参看书中第5章索引部分。

查询内嵌文档:有两种方法可以查询内嵌文档:查询整个文档,或者只针对其键/值对进行查询。

查询整个文档:与普通查询完全相同,但是要查询的子文档与子文档必须精确匹配,而且还要保证查询子文档与子文档的顺序完全相同。

针对键/值对查询:如果允许的话,通常只针对内嵌文档的特定键值进行查询,这是比较好的做法。这样,即便数据结构改变,也不会导致所有查询因为要精确匹配而一下子都挂掉。我们可以使用点表示法查询内嵌文档的键。

针对内嵌文档查询章节书中最后部分提供了一个内嵌文档作为数组元素时的查询例子,并提供了解决方案,可以去看看4.3.4。

$where查询:

当键/值对的查询方式无法满足需求时,就可以考虑使用$where查询 了,$where可以在查询中执行任意的javascript语句。因为是执行js脚本,所以几乎可以做任何事(比如注入攻击),为了安全起见应该避免使用$where(可以在启动mongod时指定--noscripting选项来完全关闭js的执行),并且它比常规查询速度要慢很多,先使用常规查询进行过滤,然后再使用$where语句,这样组合可以降低性能损失,如果可以的话使用$where前应该先使用索引进行过滤,$where只用于对结果进一步过滤。db.test.find({"$where":function(){for(field in this){console.log(field);return true;}});//函数内this指向的是当前文档,函数返回true文档就作为结果集的一部分返回,false则不返回。

复杂查询的另一种方式是使用聚合工具,参考书中第7章。

游标(这部分针对javascript shell进行介绍,可能不同的客户端程序中游标会略有不同):通常能够对最终结果进行有效的控制,限制结果的数量,略过部分结果,根据任意键按任意顺序的组合对结果进行各种排序,或者执行其他一些强大的操作。

javascript中的游标:简单来说find函数的返回值就是一个游标,游标对象有hasNext和next函数用来迭代结果。调用find时shell并不立即执行查询数据库,而是等待真正开始要求获得结果时才发送查询,这样在执行之前可以给查询附加额外的选项。几乎游标对象的每个方法都返回游标对象本身,这样就可以按任意顺序组成方法链(sort、limit、skip等游标方法用于附件查询额外的选项),当游标对象首次执行hasNext或者next时查询才会被发往服务器,shell立即获取前100个结果或者前4mb数据(两者之中最小者),这样下次调用next或者hasNext时就不必再次连接服务器取结果了,客户端用光了第一组结果,shell会再一次联系数据库,使用getMore请求提取更多的结果,getMore请求包含一个查询标示符,向数据库询问是否还有更多结果,如果有则返回下一批结果,这个过程会一直持续到游标耗尽或者结果全部返回。

游标最常用的查询选项:所有这些选项一定要在查询被发送到服务器之前指定。

limit:限制结果数量,可在find后使用limit函数,db.test.find().limit(3);//只返回3条结果,要是匹配的结果不足3个,则返回匹配数量的结果,limit指定的是上限而非下限。

skip:与limit类似,db.test.skip(10);//这个操作会略过前10个匹配的文档,然后返回余下的文档。如果结果集里的结果少于10个则不会返回任何文档。注意略过过多的结果会导致性能问题,4.5.2章提供了解决方案。

sort:接收一个对象作为参数,这个对象是一组键值对,键对应文档的键名,值代表排序的方向,排序方向可以说1(升序)或者-1(降序)。如果指定了多个键,则按照这些键被指定的顺序逐个排序。有时一个键有多种类型的值,如果对这种混合类型的键排序,其排序顺序是预先定义好的,至于如何定义请参考4.5.1章的比较顺序小节

这三个方法可以组合使用,这对于分页非常有用,这里说一个分页时常用的聚合函数:count用于返回集合中的文档数量,不论集合有多大,count都会很快返回总的文档数量,也可以给count传递一个查询文档,mongo会计算查询结果的数量,但是增加查询条件会使count变慢。

高级查询选项:绝大多数驱动程序都提供了辅助函数,用于向查询中添加各种选项。其实上面sort那些函数也都是查询选项,举个例子就明白了:db.test.find({"name":"gao"}).sort({"x":1});//实际查询时不会直接将{"name":"gao"}作为查询发送给数据库,而是先将查询封装在一个更大的文档中,比如这个例子最终的查询文档将被封装为{"$query":{"name":"gao"},"$orderby":{"x":1}}

以下的选项没有提供单独的函数,可使用_addSpecial函数指定:db.test.find()._addSpecial("$maxScan",20);

$maxscan:接受integer值,指定本次查询中扫描文档数量的上限。

$min:接受document值,查询的开始条件,在这样的查询中,文档必须与索引的键完全匹配,查询中会强制使用给定的索引。

$max:接受document值,查询的结束条件,剩下部分同上。

$showDiskLoc:接受boolean值,在查询结果中添加一个$diskLoc字段,用于显示该条结果在磁盘上的位置。

获取一致结果:如果要对查询结果文档做一些更新,如果结果集不多(少于100或小于4mb)时没有问题,如果结果集很多,mongodb可能会多次返回之前更新过的文档,这跟mongodb文档的存储机制有关,具体原理参考书中4.5.4章节或附录b或者3.3.2章第8修改器速度小节,解决方案是find().snapshot(),对查询进行快照,如果使用了这个选项,查询就在_id索引上遍历执行,这样就可以保证每个文档只被返回一次。快照会使查询变慢,应该只有在必要时使用快照。

游标的生命周期:详细请参考4.5.5章,如果希望游标持续的时间长一些,多数驱动程序都实现了一个immortal的函数,或者类似的机制,来告知数据库不要让游标超时,如果关闭了游标超时时间,一定要迭代完所有结果,或主动销毁,确保游标被关闭,否则它会一直在数据库中消耗服务器资源。

数据库命令:使用db.runCommand函数可以执行数据库命令。有些数据库命令封装的有一些辅助函数,比如db.conn.drop(),它底层执行的命令其实是db.runCommand({"drop":"coll"});Mongodb中的命令被实现为一种特殊的查询,这些特殊的查询会在$cmd集合上执行,runCommand只是接受一个命令文档,并且执行与这个命令文档等价的查询,于是,drop命令会被转换为如下代码:db.$cmd.findOne({"drop":"coll"});shell中使用db.listCommands()函数可以看到所有的数据库命令。更多数据库命令的介绍请参考4.6章。

4.3.更新文档:

db.[collection name].update({limit doc},{new doc});update至少接受两个参数,第一个是限定条件文档,第二个是新的文档。注意:mongodb一个集合内的文档结构可以不一致,我们在这里不仅可以更新文档数据还可以用来修改文档的结构。

 

如果两个更新同时发生,先到达服务器的先执行,接着执行另外一个,所以不用担心会破坏到文档。

 

常见错误:查询条件匹配到多个文档,然后更新时由于第二个参数也存在"_id"值,而产生重复"_id"的值导致数据库抛出错误,任何文档都不会更新。为了避免这种情况最好确保更新时总是指定一个唯一的文档,例如使用"_id"作为匹配条件,或者去掉第二个参数的"_id"字段。

注意"_id"字段是不可变的,一旦插入就不可再修改。

 

更新修改器:

增加、修改、或删除键时应该使用$修改器,否则更新时不会保留原来的文档结构,新的文档结构会替换掉原来的结构,比如想修改名字为"gao":db.conn.update({"_id":ObjectId("11111")},{"name":"gao"});结果更新后的结构只有name字段了。

$inc:用来增加已有键的值,或者该键不存在那就创建一个,只能用于整型,长整型或双精度浮点型的值,如果用于其他类型的数据上就会导致操作失败,另外$inc键的值必须为数字,否则也会提示错误,要修改其他类型应该使用$set或者数组修改器。例子:db.conn.update({"_id":ObjectId("11111")},{"$inc":{"num":1}});//更新num字段值加1。

$set:用来指定一个字段的值,如果这个字段不存在,则创建它。例子:db.conn.update({"_id":ObjectId("11111")},{"$set":{"num":1}});对于内嵌的文档可以用"."来指定:db.conn.update({"_id":ObjectId("11111")},{"$set":{"innerDoc.name":"inner"}});

$unset:完全删除一个键。例子:db.conn.update({"_id":ObjectId("11111")},{"$unset":{"num":1}});

数组修改器:

$push:如果数组已经存在会向已有的数组末尾加入一个元素,要是没有就创建一个新的数组。例如要为博客文章增加一个评论"comments"数组字段,可以向还不存在的"comments"数组添加一条评论,这个数组会被自动创建并加入一条评论:db.blog.posts.update({"title":"a blog title"},{"$push":{"comments":{"name":"joe","content":"nice post."}}});//注意这里是push操作,指定的comments值是一个即将push到数组里的对象,而非数组对象(数组对象应该也是支持的,因为mongodb的文档键的值是支持混合类型的)。

 

$each:可以通过一次$push操作添加多个值。如:db.blog.posts.update({"title":"a blog title"},{"$push":{"tags":{"$each":["java","js","mongodb"]}}});//如果指定的tags数组中只含有一个元素,那这个操作就等同于没有使用$each的普通$push操作。

$slice:它的值必须是一个负数,比如-10表示限制数组只保留最后加入的10个元素,如果数组元素小于10($push操作之后),那么所有元素都会被保留,如果大于10那么只有最后10个元素会被保留,因此使用$slice可以用来在文档中创建一个队列。

$sort:配合$slice在清理元素之前先使用$sort进行排序,然后再决定清除哪些元素,需要$push操作的数组是一个对象数组,而非简单类型的数组。例子:db.blog.posts.update({"title":"a blog title"},{"$push":{"student":{"$each":[{"name":"a","age":10},{"name":"b","age":12},{"name":"c","age":8}],"$slice":-10,"$sort":{"age":-1}}}});$sort的1表示升序,-1表示降序。

注意:不能只将$slice或者$sort与$push配合使用,还要使用$each。

$ne:将数组作为数据集使用,保证数组内的元素不会重复。举个例子:如果authors数组中不存在gao的元素时时再添加进去,db.papers.update({"authors":{"$ne":"gao"}},{"$push":{"authors":"gao"}});。有些时候$ne根本行不通,另一种选择是使用$addToSet,举例:db.papers.update({"_id":ObjectId("xxx")},{"$addToSet":{"authors":"gao"}});这样就保证了数组内的元素唯一了。另外可以将$addToSet和$each组合起来可以添加多个不同的值,但是$ne和$push组合就不能实现。

$pop:若是把数组看成队列或者栈,可以用$pop从数组任何一端删除元素。{"$pop":{"key":1}}//从数组末尾删除一个元素,{"$pop":{"key":-1}}//从数组头部删除。

$pull:基于特定条件来删除元素而不仅仅是依据元素位置。举例:文档todo数组[1,2,1,1,3],db.coll.update({},{"$pull":{"todo":1}});//这样todo数组内只剩下[2,3]

数组修改器只能用于包含数组值(数组类型)的键。

基于位置的数组修改器:

通过数组下标:db.blog.update({"post":post_id},{"$inc":{"comments.0.votes":1}});//更新comments第0个元素的votes属性加1

使用定位操作符$:用来定位查询文档已经匹配的数组元素,并进行更新,定位符只更新第一个匹配的元素。比如:用户john把名字改成了jim,就可以用定位符来替换他在评论中的名称:db.blog.update({"comments.author":"john"},{"$set":{"comments.$.author":"jim"}});//查询comments数组内元素的author值等于john的那个元素,然后更新author值为jim,因为不确定匹配到的john的下标位置在哪,所以使用$定位操作符来解决此问题,这里如果john发表了多个评论,只有第一条评论中的名称会被更新。

usePowerOf2Sizes:开启可提高磁盘复用率,但是在一个只进行插入或者原地更新的集合上使用这个选项,会导致写入速度变慢。db.runCommand({"collMod":collectionName,"usePowerOf2Sizes":true});

 

upsert:例子1:db.blog.update({"name":"gao"},{"$inc":{"age":1}},true);//第三个参数true表示这是一个upsert操作,即name=gao的文档存在时去正常更新,不存在时基于查询条件文档加上更新的文档内容({"name":"gao","age":1})作为一条新的文档插入到集合中。例子2:db.blog.update({"age":2},{"$inc":{"age":1}},true);//upsert会先创建一个age=2的文档,然后更新age+1,所以最后的age=3

$setOnInsert:在创建文档的同时创建字段并为他赋值,但是在之后的所有更新操作中,这个文档的数据都不再被改变。例如:db.blog.update({"_id":ObjectId("5ae1a319abc852e4aa6cb08a")},{"$setOnInsert":{"name":"gao"}},true);//如果"_id"为5ae1a319abc852e4aa6cb08a的查询文档匹配到了文档,那么文档不会被更新,如果不存在将插入一条新的文档。

save:save是一个shell函数,如果文档不存在,它会自动创建文档,如果文档存在,它会更新这个文档。它只有一个文档参数,如果这个参数含有"_id"键,save会调用upsert,否则会调用insert。

更新多个文档:

默认情况下,更新只能对符合匹配条件的第一条文档执行操作,要是有多个文档符合条件,只有第一条文档会被更新,其他文档不会发生变化,可以设置update的第4个参数为true来更新所有匹配的文档。注意:多更新只适用于$操作符($set等,上面说过的那些更新修改器)。db.runCommand({getLastError:1});命令(返回最后一次操作的相关信息)可以查看多文档更新到底更新了多少文档,返回结果"n"键的值就是更新文档数量。

返回被更新的文档:

findAndModify命令:能够在一个操作中返回匹配结果并且进行更新,

举例:

db.runCommand({

"findAndModify":"集合名称",

"query":{"key":"value"},//查询文档

"update":{"$set":{"key":"value"}}//更新文档

});

返回结果:

{

"ok":1,

"value":{

//默认返回的是修改之前的文档数据

}

}

findAndModify命令可以使用的字段:

findAndModify:字符串,集合名

query:查询文档,用于检索文档的条件

sort:排序结果的条件

update:修改器文档,用于对匹配的文档进行更新

remove:布尔类型,表示是否删除文档

new:布尔类型,表示返回更新前的文档还是更新后的文档,默认是更新前的文档。

fields:文档中需要返回的字段(可选)

upsert:布尔类型,值为true时表示这是一个upsert,默认为false

update和remove必须有一个,也只能有一个。要是没有匹配的文档,这个命令会返回一个错误。

4.4.删除文档:

db.blog.remove({limit doc});注意:remove如果没有使用任何查询限定文档参数(貌似最新版本中必须有一个查询参数),它将会删除集合内的所有文档,但不会删除集合本身以及集合的元信息。删除是永久性的,不能撤销也不能恢复。

如果要清空整个集合,那么使用drop直接删除集合会更快,但是不能指定任何限定条件,并且集合本身也被删除了,元数据也都不见了。

数据库设计方面总结:

设计mongodb数据库时推荐使用子集合,比如一个博客功能的应用可能包含两个集和posts和authors,那么我们可以先建立一个父集合比如blog,那么子集合命名到blog集合下,最终命名为blog.posts,blog.authors。这样的命名使组织结构看起来更加清晰,注意子集合并没有任何特别的属性,它只是一种命名方式。

 

以上内容参考mongodb权威指南第2版,关于java如何与mongodb进行交互可参看mongodb入门经典

posted on 2018-04-28 17:01  代码ok  阅读(1145)  评论(0编辑  收藏  举报