MongoDB--修改和查询
来源:互联网 发布:山西省建筑业网络快报 编辑:程序博客网 时间:2024/04/29 06:39
为什么要介绍这些
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.0connection 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查询是,可能会比较麻烦,这里有个简便点的写法即使用$elemMatchdb.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的聚合框架,更是将这个特性发挥到最大。
- MongoDB--修改和查询
- mongoDB的高级查询和高级修改
- Mongodb嵌套查询及修改
- MongoDb的添加,查询,修改
- mongodb 增加、删除、修改、查询
- mongoDB的查询与修改
- Mongodb嵌套查询及修改
- MongoDB学习二--MongoDB 数据结构和查询
- mongoDB 之 查询和新增
- MongoDB查询、索引和聚合
- MongoDB 删除和查询文档
- php操作MongoDB基础教程(连接、新增、修改、删除、查询)
- mongoDB集合 文档创建修改删除以及查询命令总结
- mongoDB集合 文档创建修改删除以及查询命令总结
- php操作MongoDB基础教程(连接、新增、修改、删除、查询)
- MongoDB:4-MongoDB的索引和查询分析(explain)
- mongodb删除数据和修改数据
- Mongodb增加、删除和查询操作
- [Android] ImageView.ScaleType设置图解
- java与C之间的通信
- GC算法精解(复制算法与标记/整理算法)
- node.js笔记(3)
- vb.net 2010下求最大值、最小值及两种排序方法
- MongoDB--修改和查询
- Ubuntu安装StaruUML
- encode_one_frame ()中几个主要函数说明
- Maven工程的pro.xml报错处理
- 关于应用Java创建泛型创建链表
- 2016-10-11课后练习
- java中的break与continue用法
- Java:注解(Annotation)深度理解 自定义注解
- 44. Wildcard Matching