MongoDB基础学习
来源:互联网 发布:flexpaper flash.js 编辑:程序博客网 时间:2024/05/24 06:36
一. 基本概念
- 文档
文档是有序集合里面的一个键值对的有序集合。文档的键是字符串(除了少数情况,键可以用任何的UTF-8)。相当于关系型数据库当中的表table。 - 集合
集合就是一组文档,相当于关系型数据库当中的一行数据。
二. 数据类型
- null
- 布尔型true or false
- 数值型
默认为64位的浮点型数值,如果要使用整形值,可以使用NumberInt类(表示4字节带符号整数)或NumberLong类(表示8字符带符号整数),如
{"x":NumberInt("3")}
{"x":NumberLong("3")}
- 字符串
- 日期
如{“x”:new Date()} - 正则表达式,语法于JavaScript的正则表达式语法相同。
- 数组
数组列表或数据集可以表示为数组:
{"x":["a","b","c"]}
- 内嵌文档
文档可以嵌套其他文档,被嵌套的文档作为父文档的值。如:
{"x":{"y":NumberInt("3")}}
- 对象id
对象id是一个12字节的ID,是文档的唯一标识。
{"x",ObjectId()}
- 二进制数据
- 代码
查询和文档可以包含任意的JavaScript代码:
{"x":function(){/* ... */}}
三. 创建、更新和删除文档
1. 操作
插入文档
插入一个文档db.foo.insert({"bar":"baz"})
批量插入db.foo.batchInsert({"_id":0},{"_id":1},{"_id":2})
删除文档
删除文档db.foo.remove()
db.foo.remove({"opt_out":true})
如果要删除全部的文档,使用drop直接删除集合会更快。更新文档
文档存入数据库后,就可以使用update方法来更新文档。update有两个参数,一个是查询文档,用于定位需要更新的目标文档;另一个是修改器文档,用于说明要对找到的文档进行那些修改。
文档的修改可以分为两种类型,一种是文档的替换,就是将文档内容整个地替换掉。另外一种是文档的部分字段的更新。在进行文档的部分字段的更新时,必须使用修改器,否则文档会被全部替换。
db.user.update({"name":"joe"},{"address":"12345"})db.user.update({"name":"joe"},{"$set":{"address":"12345"}})
第一个更新操作会将name为Joe的文档替换掉,第二个更新操作会将name为joe的文档的address内容替换为12345。因此,在修改文档的字段内容的时候,必须使用修改器。
update函数的第三个参数为一个布尔型的值,指示update函数是否为upset。当为true(即upset)时,要是没有找到符合更新条件的文档,就会以这个条件和更新文档为基础创建一个新的文档。如果找到了匹配的文档,则进行正常的更新。
update函数的第四个参数为一个布尔型的值,用于指示是否更新所有匹配的文档。update默认情况下只更新第一个匹配到的文档。因此,如果要更新所有匹配的文档,则需要将改参数设置为true。
2.常用的修改器
$set 用于设置文档中某一个键对应的值,如果对应的键不存在,则会新增加一个键值对。
$inc 用于增加已有键的值,如果对应的键不存在那就创建一个。$set只能用于整形,长整形或者双精度浮点型的值。
$push 用于操作数组。如果数组已经存在,$push会向已有的数组末尾加入一个元素,要是没有则会创建一个数组。
db.stocker.update({"_id":"GOOD"},{"$push":{"comment":"123"}})
如果_id为GOOD的文档中不存在comment键,则新创建一个,如果存在的话,则将123添加到comment键的值当中,成为一个数组。
也可以和$each一起使用:
db.stocker.update({"_id":"GOOD"},{"$push":{"comment":{"$each":["123","456","789"]}}})
这样,三个字符串就都被添加到comment键对应的数组当中了。
$ne $andToSet 当我们将数组座位数据集使用的时候,需要保证数组内的元素不会重复,可以使用$ne $andToSet。
$pull 用于删除数组当中的元素。
四. 查询
1. find函数
MongoDB数据查询使用find函数,其功能与SQL中的select函数相同,可提供与关系型数据库类似的许多功能,包含映射、排序等。
find函数语法
db.COLLECTION_NAME.find(query,fields,limit,skip)
find() 方法以非结构化的方式来显示所有文档。
如果你需要以易读的方式来读取数据,可以使用 pretty() 方法,语法格式如下:
db.COLLECTION_NAME.find().pretty()
pretty() 方法以格式化的方式来显示所有文档。
参数说明:
- query:指明查询条件,相当于SQL中的where语句。
db.account.find({name:"lewesyang",age:{$it:22}})
- fields:用于字段映射,指定是否返回该字段,0代表不返回,1代表返回
db.account.find({name:"lewesyang",age:{$it:22}},{"age":0})
- limit:限制查询结果集的文档数量,指定查询返回结果数量的上限
db.account.find({name:"lewesyang",age:{$it:22}},{"age":0},5)
- skip:跳过一定数据量的结果,设置第一条返回文档的偏移量
db.account.find({name:"lewesyang",age:{$it:22}},{"age":0},5,10)
单独使用limit和skip语法:
db.account.find().limit(5).skip(10)
注意事项:
- MongoDB不支持多集合间的连接查询,find函数一次查询只能针对一个集合。
- find参数为空或者查询条件为空文档时,会返回集合中的所有文档。
- 除了将limit和skip作为find函数的参数外,还可以单独使用limit和skip函数来修饰查询结果。
- 返回的查询结果集默认情况下是无序的,如果需要对结果进行排序,可以使用sort函数:
db.account.find().sort({age:-1})
- db.collection.findOne()只会返回第一条数据。
- 当查询的集合文档数量很大时,为了加快数据的查询速度可以创建索引。
- 除了使用find函数实现基本查询外,MongoDB还提供了聚合框架,用于复杂查询。
2. 查询条件
- 比较操作符
$gte,$gt,$lte,$lt,$ne,特别对应>=、>、<=、<。可以将其组合起来以方便查找一个范围的值。db.user.find("age":{"$gte":18,"$lte":25,"$ne":22})
- OR查询
MongoDB当中有两种方式进行OR查询,$in可以用来查询一个键的多个值,$or更通用一些,可以在多个键当中查询任意的给定值,$nin的作用域$in相反。db.raffle.find({"age":{"$in":[1,2,3]}})
db.raffle.find({"$or":[{"age":12},{"sex":"man"}]})
- $not
$not时原条件句,即可以用在任何其他条件上。db.raffle.find({"age":{"not":{"$in":[1,2,3]}}})
作用和db.raffle.find({"age":{"$nin":[1,2,3]}})
相同 - 条件语义
我们会发现以$开头的键位于不同的位置。在查询当中,”$lte”在内层文档,在更新当中,”$inc”位于外层文档。基本可以肯定:条件语句是内层文档的键,而修改器则是外层文档的键。有一些“元操作符”也位于外层文档中,比如“\$and”,“\$or”,“\$nor”等。一个键可以有任意多个条件语句,但是一个健不能对应多个更新修改器。
3. 特定类型的查询
3.1 null
null类型有些奇怪,它不仅能够匹配自身,也能够匹配不包含自己的键的值。例如:
{"_id":ObjectId("123"),"y":null}{"_id":ObjectId("123"),"y":1}{"_id":ObjectId("123"),"y":2}
当我们使用查询语句: db.c.find({"y":null})
时,不仅能够查询到第一条数据,也能够查询到第二条数据。因此,为了解决该问题,应该使用查询语句: db.c.find({"y":{"$in":[null],"$exists":true}})
来进行查询。
3.2 正则表达式
可以使用 db.user.find({"name":/joe/i})
来匹配name键值包含joe字串的文档。在使用正则表达式时,需要注意的是,正则表达式不区分大小写。MongDB使用Perl兼容的正则表达式(PCRE)库来匹配正则表达式,任何PCRE支持的正则表达式语法都能被Perl接受。
3.3 查询数组
查询数组很容易,对于数组,我们可以这样理解:数组中每一个元素都是这个键值对键的一个有效值,如下面的例子:我们要查询出售apple的水果店:
db.fruitshop.find(); { "_id" : ObjectId("5022518d09248743250688e0"), "name" : "big fruit", "fruits" : [ "apple", "pear", "orange" ] } { "_id" : ObjectId("502251a309248743250688e1"), "name" : "good fruit", "fruits" : [ "banana", "pear", "orange" ] } { "_id" : ObjectId("502251c109248743250688e2"), "name" : "good fruit", "fruits" : [ "banana", "apple", "tomato" ] } > db.fruitshop.find({"fruits":"apple"}); { "_id" : ObjectId("5022518d09248743250688e0"), "name" : "big fruit", "fruits" : [ "apple", "pear", "orange" ] } { "_id" : ObjectId("502251c109248743250688e2"), "name" : "good fruit", "fruits" : [ "banana", "apple", "tomato" ] }
我们发现只要包含苹果的数组都能被查询出来。如果要通过多个元素来匹配数组,就需要条件操作符”$all”,比如我们要查询既卖apple又卖banana的水果店:
db.fruitshop.find(); { "_id" : ObjectId("5022518d09248743250688e0"), "name" : "big fruit", "fruits" : [ "apple", "pear", "orange" ] } { "_id" : ObjectId("502251a309248743250688e1"), "name" : "good fruit", "fruits" : [ "banana", "pear", "orange" ] } { "_id" : ObjectId("502251c109248743250688e2"), "name" : "good fruit", "fruits" : [ "banana", "apple", "tomato" ] } > db.fruitshop.find({"fruits":{"$all":["apple","banana"]}}); { "_id" : ObjectId("502251c109248743250688e2"), "name" : "good fruit", "fruits" : [ "banana", "apple", "tomato" ] }
我们看,使用“$all”对数组内元素的顺序没有要求,只要全部包含的数组都能查询出来。数组查询也可以使用精确匹配的方式,即查询条件文档中键值对的值也是数组,如:
{ "_id" : ObjectId("5022518d09248743250688e0"), "name" : "big fruit", "fruits" : [ "apple", "pear", "orange" ] } { "_id" : ObjectId("5022535109248743250688e4"), "name" : "fruit king", "fruits" : [ "apple", "orange", "pear" ] } { "_id" : ObjectId("502253c109248743250688e5"), "name" : "good fruit", "fruits" : [ "apple", "orange", "pear", "banana" ] } > db.fruitshop.find({"fruits":["apple","orange","pear"]}); { "_id" : ObjectId("5022535109248743250688e4"), "name" : "fruit king", "fruits" : [ "apple", "orange", "pear" ] }
如果是精确匹配的方式,MongoDB的处理方式是完全相同的匹配,即顺序与数量都要一致,上述中第一条文档和查询条件的顺序不一致,第三条文档比查询条件文档多一个元素,都没有被匹配成功!
对于数组的匹配,还有一种形式是精确指定数组中某个位置的元素匹配,我们前面提到,数组中的索引可以作为键使用,如我们要匹配水果店售第二种水果是orange 的水果店:
db.fruitshop.find(); { "_id" : ObjectId("5022518d09248743250688e0"), "name" : "big fruit", "fruits" : [ "apple", "pear", "orange" ] } { "_id" : ObjectId("5022535109248743250688e4"), "name" : "fruit king", "fruits" : [ "apple", "orange", "pear" ] } { "_id" : ObjectId("502253c109248743250688e5"), "name" : "good fruit", "fruits" : [ "apple", "orange", "pear", "banana" ] } > db.fruitshop.find({"fruits.1":"orange"}); { "_id" : ObjectId("5022535109248743250688e4"), "name" : "fruit king", "fruits" : [ "apple", "orange", "pear" ] } { "_id" : ObjectId("502253c109248743250688e5"), "name" : "good fruit", "fruits" : [ "apple", "orange", "pear", "banana" ] }
数组索引从0开始,我们匹配第二种水果就用furits.1作为键。
$size条件操作符,可以用来查询特定长度的数组的,如我们要查询卖3种水果的水果店:
db.fruitshop.find(); { "_id" : ObjectId("5022518d09248743250688e0"), "name" : "big fruit", "fruits" : [ "apple", "pear", "orange" ] } { "_id" : ObjectId("5022535109248743250688e4"), "name" : "fruit king", "fruits" : [ "apple", "orange", "pear" ] } { "_id" : ObjectId("502253c109248743250688e5"), "name" : "good fruit", "fruits" : [ "apple", "orange", "pear", "banana" ] } > db.fruitshop.find({"fruits":{"$size":3}}); { "_id" : ObjectId("5022518d09248743250688e0"), "name" : "big fruit", "fruits" : [ "apple", "pear", "orange" ] } { "_id" : ObjectId("5022535109248743250688e4"), "name" : "fruit king", "fruits" : [ "apple", "orange", "pear" ] }
但条件操作符”$size”不能和其他操作符连用如“$gt”等,这是这个操作符的一个缺陷。使用这个操作符我们只能精确查询某个长度的数组。如果实际中,在查询某个数组时,需要按其长度范围进行查询,这里推荐的做法是:在这个文档中额外增加一个“size”键,专门记录其中数组的大小,在对数组进行”$push”操作同时,将这个“size”键值加1。如下所示:
db.fruitshop.find({"name":"big fruit"}); { "_id" : ObjectId("5022518d09248743250688e0"), "fruits" : [ "apple", "pear", "orange", "strawberry" ], "name" : "big fruit", "size" : 4 } db.fruitshop.update({"name":"big fruit"}, ... {"$push":{"fruits":"banana"}, "$inc":{"size":1}}, false, false); > db.fruitshop.find({"name":"big fruit"}); { "_id" : ObjectId("5022518d09248743250688e0"), "fruits" : [ "apple", "pear", "orange", "strawberry", "banana" ], "name" : "big fruit", "size" : 5 }
find函数的第二个参数用于查询返回哪些键,他还可以控制查询返回数组的一个子数组,如下例:我只想查询水果店售卖说过数组的前两个:
db.fruitshop.find(); { "_id" : ObjectId("5022518d09248743250688e0"), "fruits" : [ "apple", "pear", "orange", "strawberry", "banana" ], "name" : "big fruit" } { "_id" : ObjectId("5022535109248743250688e4"), "fruits" : [ "apple", "orange", "pear" ], "name" : "fruit king" } { "_id" : ObjectId("502253c109248743250688e5"), "fruits" : [ "apple", "orange", "pear", "banana" ], "name" : "good fruit" } > db.fruitshop.find({}, {"fruits":{"$slice":2}}); { "_id" : ObjectId("5022518d09248743250688e0"), "fruits" : [ "apple", "pear" ], "name" : "big fruit" } { "_id" : ObjectId("5022535109248743250688e4"), "fruits" : [ "apple", "orange" ], "name" : "fruit king" } { "_id" : ObjectId("502253c109248743250688e5"), "fruits" : [ "apple", "orange" ], "name" : "good fruit" }
“$slice”也可以从后面截取,用复数即可,如-1表明截取最后一个;还可以截取中间部分,如[2,3],即跳过前两个,截取3个,如果剩余不足3个,就全部返回!
db.fruitshop.find(); { "_id" : ObjectId("5022518d09248743250688e0"), "fruits" : [ "apple", "pear", "orange", "strawberry", "banana" ], "name" : "big fruit" } { "_id" : ObjectId("5022535109248743250688e4"), "fruits" : [ "apple", "orange", "pear" ], "name" : "fruit king" } { "_id" : ObjectId("502253c109248743250688e5"), "fruits" : [ "apple", "orange", "pear", "banana" ], "name" : "good fruit" } > db.fruitshop.find({}, {"fruits":{"$slice":-1}}); { "_id" : ObjectId("5022518d09248743250688e0"), "fruits" : [ "banana" ], "name" : "big fruit" } { "_id" : ObjectId("5022535109248743250688e4"), "fruits" : [ "pear" ], "name" : "fruit king" } { "_id" : ObjectId("502253c109248743250688e5"), "fruits" : [ "banana" ], "name" : "good fruit" } > db.fruitshop.find({}, {"fruits":{"$slice":[3,6]}}); { "_id" : ObjectId("5022518d09248743250688e0"), "fruits" : [ "strawberry", "banana" ], "name" : "big fruit" } { "_id" : ObjectId("5022535109248743250688e4"), "fruits" : [ ], "name" : "fruit king" } { "_id" : ObjectId("502253c109248743250688e5"), "fruits" : [ "banana" ], "name" : "good fruit" }
如果第二个参数中有个键使用了条件操作符”$slice”,则默认查询会返回所有的键,如果此时你要忽略哪些键,可以手动指明!如:
db.fruitshop.find({}, {"fruits":{"$slice":[3,6]}, "name":0, "_id":0}); { "fruits" : [ "strawberry", "banana" ] } { "fruits" : [ ] } { "fruits" : [ "banana" ] }
3.4 查询内嵌文档
查询文档有两种方式,一种是完全匹查询,另一种是针对键值对查询!内嵌文档的完全匹配查询和数组的完全匹配查询一样,内嵌文档内键值对的数量,顺序都必须一致才会匹配,如下例:
db.staff.find(); { "_id" : ObjectId("50225fc909248743250688e6"), "name" : { "first" : "joe", "middle" : "bush", "last" : "Schmoe" }, "age" : 45 } { "_id" : ObjectId("50225fe209248743250688e7"), "name" : { "first" : "joe", "middle" : "bush" }, "age" : 35 } { "_id" : ObjectId("50225fff09248743250688e8"), "name" : { "middle" : "bush", "first" : "joe" }, "age" : 25 } > db.staff.find({"name":{"first":"joe","middle":"bush"}}); { "_id" : ObjectId("50225fe209248743250688e7"), "name" : { "first" : "joe", "middle" : "bush" }, "age" : 35 }
针对内嵌文档特定键值对的查询是最常用的!通过点表示法来精确表示内嵌文档的键:
db.staff.find(); { "_id" : ObjectId("50225fc909248743250688e6"), "name" : { "first" : "joe", "middle" : "bush", "last" : "Schmoe" }, "age" : 45 } { "_id" : ObjectId("50225fe209248743250688e7"), "name" : { "first" : "joe", "middle" : "bush" }, "age" : 35 } { "_id" : ObjectId("50225fff09248743250688e8"), "name" : { "middle" : "bush", "first" : "joe" }, "age" : 25 } > db.staff.find({"name.first":"joe", "name.middle":"bush"}); { "_id" : ObjectId("50225fc909248743250688e6"), "name" : { "first" : "joe", "middle" : "bush", "last" : "Schmoe" }, "age" : 45 } { "_id" : ObjectId("50225fe209248743250688e7"), "name" : { "first" : "joe", "middle" : "bush" }, "age" : 35 } { "_id" : ObjectId("50225fff09248743250688e8"), "name" : { "middle" : "bush", "first" : "joe" }, "age" : 25 }
我们看,这样查询,所有有效文档均被查询到了!通过点表示法,可以表示深入到内嵌文档内部的键!利用“点表示法”来查询内嵌文档,这也约束了在插入文档时,任何键都不能包含“.” !!
当内嵌文档变得复杂后,如键的值为内嵌文档的数组,这种内嵌文档的匹配需要一些技巧,如下例:
> db.blogs.findOne(); { "_id" : ObjectId("502262ab09248743250688ea"), "content" : ".....", "comment" : [ { "author" : "joe", "score" : 3, "comment" : "just so so!" }, { "author" : "jimmy", "score" : 5, "comment" : "cool! good!" } ] } > db.blogs.find({"comment.author":"joe", "comment.score":{"$gte":5}}); { "_id" : ObjectId("502262ab09248743250688ea"), "content" : ".....", "comment" : [ { "author" : "joe", "score" : 3, "comment" : "j ust so so!" }, { "author" : "jimmy", "score" : 5, "comment" : "cool! good!" } ] }
我们想要查询评论中有叫“joe”并且其给出的分数超过5分的blog文档,但我们利用“点表示法”直接写是有问题的,因为这条文档有两条评论,一条的作者名字叫“joe”但分数只有3,一条作者名字叫“jimmy”,分数却给了5!也就是这条查询条件和数组中不同的文档进行了匹配!这不是我们想要的,我们这里是要使用一组条件而不是单个指明每个键,使用条件操作符“$elemMatch”即可!他能将一组条件限定到数组中单条文档的匹配上:
> db.blogs.findOne(); { "_id" : ObjectId("502262ab09248743250688ea"), "content" : ".....", "comment" : [ { "author" : "joe", "score" : 3, "comment" : "just so so!" }, { "author" : "jimmy", "score" : 5, "comment" : "cool! good!" } ] } > db.blogs.find({"comment":{"$elemMatch":{"author":"joe", "score":{"$gte":5}}}}); > db.blogs.find({"comment":{"$elemMatch":{"author":"joe", "score":{"$gte":3}}}}); { "_id" : ObjectId("502262ab09248743250688ea"), "content" : ".....", "comment" : [ { "author" : "joe", "score" : 3, "comment" : "j ust so so!" }, { "author" : "jimmy", "score" : 5, "comment" : "cool! good!" } ] }
这样做,结果是正确的!利用条件操作符“$elemMatch”可以组合一组条件,并且还能达到的“点表示法”的模糊查询的效果!
- Mongodb基础操作学习
- 笔记:MongoDB 基础学习
- MongoDB基础学习
- mongodb基础学习
- MongoDB基础学习
- MongoDB基础学习笔记
- MongoDB 基础学习
- MongoDB学习笔记(管理基础)
- node基础学习--mongodb数据库
- MongoDB基础学习一 ---- MongoDB的基本使用
- MongoDB基础学习二----MongoDB中常用的索引操作
- MongoDB基础学习三 ---- MongoDB的常用聚合操作
- mongoDB学习(二)——mongoDB的基础操作
- mongodb学习记录之一:基础查询
- mongodb学习(一)——基础入门
- MongoDB学习笔记(0):NoSQL基础
- MongoDb数据库学习基础语法(一)
- MongoDb数据库学习基础语法(二)
- 关于switch语句
- Unity踩坑记..
- hexo3添加百度统计
- MySQL 5.6 for Windows 解压缩版配置安装
- 目标检测网络发展历程从R-CNN到Faster-RCNN
- MongoDB基础学习
- 蓝桥杯 历届试题 买不到的数目 解题报告(完全背包,数论)
- java基础学习笔记之String、StringBuffer、StringBuilder
- 拖动图片到 Python 脚本,自动生成 Markdown 格式链接
- JAVA properties文件的读取
- 【网络爬虫项目】实战知识点
- hdoj2149Public Sale
- android CCD
- Nginx运行日志自动切割