未加星标

MongoDB--修改和查询

字体大小 | |
[数据库(综合) 所属分类 数据库(综合) | 发布者 店小二05 | 时间 2016 | 作者 红领巾 ] 0人收藏点击收藏
为什么要介绍这些

MongoDB作为一个通用性数据库,从基本概念和一些操作的具体实现上跟mysql等关系型数据库不太一样。这导致MongoDB有许多特性的语法。本文主要从MongoDB的修改,查询以两个方面去看这些特性。

MongoDB Shell
为什么要介绍MongoDB Shell?因为MongoDB Shell是我们学习MongoDB至关重要的工具。MongoDB Shell是一个javascript shell,可以在shell中使用命令行与MongoDB实例交互。
当安装好MongoDB之后,通过命令
mongod --config /path/mongod.conf

启动MongoDB实例。然后通过命令

mongo

去链接本地的MongoDB实例,一般会得到输出结果

MongoDB shell version:2.4.0
connection to: test
>
第一行表示了MongoDB的版本,第二行表示连接到的MongoDB库,默认就是test库。在第三行就能输入需要使用的命令了。
既然是一个JavaScript shell,那么它能够执行一些JavaScript的程序(这不是本章主要讨论的内容),更重要的是,它是一个连接MongoDB的客户端。通过db命令可以查看当前的库是什么,use {dbname}能够切换库,show dbs可以查看所有的库,show collections可以查看库下所有的集合。
MongoDB的修改

上一篇文章《MongoDB基础知识》中简单的介绍过插入文档,更新文档,删除文档的操作。插入删除等都比较简单,MongoDB的更新语法比较多样化。

1.第一种方法适用于大量的文档修改,语法如下

db.{collectionName}.update({criteria},{document})

criteria指的是查询条件的文档,后面的document是需要条换的文档。如

>var joe = db.users.findOne({"name":"joe"});
>joe.age = 20;
>...//一堆修改
>db.users.update({"name":"joe"}, joe);
通过语法可以将name为joe的文档替换成新的joe文档。
2.$set修改器
如果习惯MySQL的语法,那么对于修改都是set后面接上一串fieldName=value。MongoDB其实也有类似的功能,它就是$set。下面是$set的用法
> db.users.update({"_id" : ObjectId("4b253b067525f35f94b60a31")},{"$set" : {"favorite book" : "War and Peace"}})

这段语句就是将_id为ObjectId(“4b253b067525f35f94b60a31”)的文档中的key为favorite book的值改成War and Peace。因为MongoDB的文档很灵活,$set是可以改变key的类型,如原来favorite book的值是字符串,但是它也能改成数组

> db.users.update({"_id" : ObjectId("4b253b067525f35f94b60a31")},{"$set" : {"favorite book" : ["War and Peace", "Cat's Cradle",...]}})

与MySQL不同的是,如果MySQL中需要删除一个字段的值,只能将字段的value设置成null,空字符串或者0之类的数值。但是MongoDB是通过另外一个操作$unset

> db.users.update({"_id" : ObjectId("4b253b067525f35f94b60a31")},{"$unset" : {"favorite book" : 1}})
这个操作其实是将这个键给删除了,即再次查询文档,就没有键favorite boo了。当然,还可以通过$set又将它加上。
最后需要说明的是,$set在级联文档中的作用是一样的
db.blog.posts.update({"author.name" : "joe"},{"$set" : {"author.name" : "joe schmoe"}})
这样就会把blog.posts集合的内嵌文档author中的name属性改掉。
3.增加和减少
MongoDB中对value为数值的键的操作是通过修改器$inc,如
>db.games.insert({"game" : "pinball", "user" : "joe"})
>db.games.update({"game" : "pinball", "user" : "joe"},{"$inc" : {"score" : 50}})
>db.games.findOne()
{
"_id" : ObjectId(...),
"game" : "pinball",
"user" : "joe",
"score" : 50
}
score这个键原来并不存在,所以“$inc”创建了这个键,并把值设定成增加量:50。$inc只能作用于整型、长整形或双精度浮点型的值。
4.修改数组
$push
>db.blog.posts.update({"title":"A blog post"}, {"$push" : {"comments" : {"name" : "joe", "email" : "...", "content" : "..."}}})
上面示例即找到title为A blog post的文档,然后将一个comment的子文档插入到该文档的comments字段中,comments字段是一个数组。在执行操作前,comments可以不存在。
- $each
db.stock.ticker.update({"_id" : "GOOG", {"$push" : {"hourly" : {"$each" : [22,33,44]}}}})
上面示例即找到_id为GOOG的文档,然后将数组[…]中的每一项逐个插入到hourly字段中。
- $slice
db.movies.update({"genre" : horror},{"$push" : {"top10" : {"$each" : ["Nightmare on Elm Street", "Saw"], "$slice" : -10}}})
上面示例表示,将一个数组的电影插入到文档的top10字段中,但是仅保留最后的10个。$slice只能是负数。
- $addToSet
$addToSet跟$push字段的含义差不多,不一样的是,$addToSet不会加入重复的数据。
- $pop
$pop的用法与$push类似,它把数组看成一个队列或者栈,它能够指定从哪个地方删除元素。如
{"$pop" : {"{key}" : 1 | -1}}

1表示从数组末尾删除,-1表示从头删除。

对于数组还有两个需要知道的东西是数字下标和定位符($)。数字下表如:

comments.0.votes
表示comments数组的第一个子文档的votes字段。
而定位符$
comments.$.author

指的是改变匹配上的文档的comments数组中的子文档author字段,但是$定位符只改变匹配上的第一个文档。

MongoDB中有个特性叫upsert,这指的是,如果匹配的文档没有,那么直接做插入操作。要使用该特性,需要为update函数加上第三个参数,并置为true。

db.analytics.update({"url" : "/blog", {"$inc" : {"pageviews" : 1}}, true})

MongoDB中有个操作符叫做$setOnInsert,从字面上看就是在insert的时候设置。比如说createTime这种字段,只需要在第一次创建的时候设置一次就可以了,之后无需更改,就可以使用这个操作符来替代$set。

默认情况下,update只会更新匹配上的第一个文档,如果想要更新所有的文档,需要将update函数的第四个参数设置成true。

MongoDB的查询

在MongoDB中想要查询,需要使用函数find

选取返回字段

想要制定返回的字段,需要设置find函数的第二个参数。

db.user.find({},{"username":1,"email":1})

上面示例表示返回username和email两个字段,如果将1指定成0,那么就是不返回该字段。

查询条件

查询条件需要写在find函数的第一个参数中。

db.users.find({"username" : "joe"})
上面示例指的是查找users集合中username为joe的文档。这种查询方式相当于是MySQL中的=。
那么如果字段做其它操作呢?
- 数值运算:$lt,$lte,$gt,$gte,$mod
这四个操作符分别对应<,<=,>,>=,分别是less than,less than and equal,greater than,greater than and equal的缩写。
db.users.find({"age" : {"$gte" : 18, "lte" : 30}})
上面示例表示找出年龄大于等于18岁,小于等于30岁的用户文档。
MongoDB还有取模运算符:
db.users.find({"id_num" : {"$mod" : [5, 1]}})

$mod后跟着的两个数字,5表示需要去除的数字,1表示需要保留下来的值。上面语句即为:id_num%5==1

$or
如果我们在条件中指定多个匹配项,如
db.users.find({"name" : "joe", "age" : 18})

上面示例表示,找到name为joe,年龄是18岁的用户文档。这是一个典型的and操作。那么如何使用or呢?没错,就是$or操作符。

db.users.find({"$or" : [{"name" : "joe"}, {"age" : 18}]})

上面示例表示找到name为joe或者年龄为18的文档。

$not

db.users.find({"age" : {"$not" : 10}})

上面示例表示查找age部位10的users文档

$in和$nin
这两个操作符很好理解,一个表示在范围内,一个表示不在范围内
db.users.find({"age" : {"$in" : [12,13,14]}})
db.users.find({"age" : {"$nin" : [12,13,14]}})
$exists
这个操作符表示存不存在。谈到这个操作符的时候不得不先说一下MongoDB中的一个特殊的类型null。null本身是一个类型,你可以这么使用它
db.users.find("blog" : null)

这个语句查询的是blog字段为null的文档。但是它不仅仅能匹配上字段值为null的文档,如果文档没有blog字段,它也会被匹配上。那么如何精确的达到我们的目的呢,这就需要$exists出马了。

db.users.find("blog" : {"$in" : [null], "$exists" : true})

这就表示必须要blog字段存在,才是复合要求的文档。(注意这里为什么用$in。因为1、如果你直接使用:那么后面应该跟的是值,而不是文档。2、没有$eq操作符)

$size
$size操作符其实是跟数组有关系的,它能获取数组的大小。
db.users.find("star" : {"$size" : 3})

这个查询表示查找star里有3个好评的用户文档。

$slice
这里又出现了一个$slice,这个$slice也是表示去除部分数据,但是此处的$slice可以使用正整数也可以使用负整数。正整数表示保留前n个数组元素,而负整数表示保留最后n个元素。
$elemMatch
对于子文档的查询,一般我们使用类似{“comments.author” : “joe”}即可。但是如果涉及到使用子文档的多个key查询是,可能会比较麻烦,这里有个简便点的写法即使用$elemMatch
db.blog.find({"comments" : {"$elemMatch" : {"author" : "joe", "score" : {"$gte" : 4}}}})
$where
在文章开头我们简介过MongoDB shell,它的实质是一个JavaScript shell。$where的用法就是可以在查询语句中使用函数如{“$where” : function}

顺便介绍一下,我们大部分时候在Terminal中查询,都不会接收find函数的返回值。查找的文档会直接被输出在Terminal中。其实find函数是有返回值的,它的返回值是一个游标。这个游标可以像JavaScript中的数组一般使用,如果使用hasNext,next接口可以在while语句中使用。如果使用forEach可以传入一个function。

简单查询和封装查询
在前面我们使用的查询如db.foo.find({“foo” : “bar”})就是一个简单查询。但是如果涉及到例如排序
db.foo.find({"foo" : "bar"}).sort({"x" : 1})

实际情况不是直接把查询{“foo” : “bar”}发送到数据库,而是把整个查询封装成另外一个文档{“$query” : {“foo” : “bar”}, “$orderby” : {“x” : 1}},然后发送给数据库。

$maxscan,$min,$max和$showDiskLoc
这届都是特殊的查询选项,分别表示最大扫描数量,索引最小范围,索引最大范围以及展示磁盘位置。
db.foo.find(criteria)._addSpecial("$maxscan", 20)
即表示最大扫描20个文档。
而$min和$max指定查询的键必须和索引完全匹配。一个表示下界一个表示上界,而在平时的查询中我们一般使用$gt和$lt去替代。
最后$showDiskLoc如果指定为true那么会在返回的文档中增加一个$diskLoc子文档,表示文档在哪个file中,并且它所处的offset是多少。
- 函数min,max,limit,skip和sort
find函数并不是语句的终结,它还能带上min,max,limit,skip,sort等函数。很好理解,min和max表示指定某个字段的下界和上界
db.foo.find().min({"x":10}).max({"x":20})

表示x最小是10,最大是20,这里不包含equal。

sort是个排序函数,最匹配的结果文档进行指定排序。

db.foo.find().sort({"x" : 1 | -1});

如果指定为1,表示升序,如果是-1,表示降序。

limit是限制返回的个数,而skip表示跳过多少个文档。这两个函数组合使用可以实现分页效果。

db.foo.find().skip(10).limit(10)

即表示跳过10个文档,取接下来的10个文档。但是需要注意的是,如果略过大量的文档,可能会产生性能问题。

总结
本文主要介绍了MongoDB中修改和查找相关的语法特性。可以看出MongoDB的语法虽然跟MySQL有比较大的差别,但是功能上是一个不缺。但是因为某些实现方式不太一样,在使用的时候需要注意。(比如分页的操作)
需要注意的是,针对MongoDB的操作大都是通过函数和文档来表达的。如果update,save,find,sort,skip,limit等函数。而每个函数的参数,大都是需要传入一个文档(即一个类似json对象的结构体)。这中语法思路贯穿了整个MongoDB,在之后的文章将讲述MongoDB的聚合框架,更是将这个特性发挥到最大。

本文数据库(综合)相关术语:系统安全软件

分页:12
转载请注明
本文标题:MongoDB--修改和查询
本站链接:http://www.codesec.net/view/483650.html
分享请点击:


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 数据库(综合) | 评论(0) | 阅读(37)