MongoDB基本语法

网络教程如下:

http://www.yiibai.com/mongodb/mongodb_environment.html

Mongodb:是一种NoSQL数据库,NoSQL:Not Only SQL

SQL: 数据表->JDBC读取->POJO(VO、PO)->控制层转化为JSON数据->客户端

这种转换太麻烦了,如果有直接数据库存放要显示的内容,就能够省略所有需要进行转换的过程。

所以在实际开发中,往往除了关系型数据库之外还要提供一个NoSql数据库,其中NoSql数据库负责数据的读取,因为直接保存的就是JSON(前提:MongoDB中的数据是排列好的组合数据)。

例如:现在要求显示出每个雇员的编号、姓名、部门名称、部门位置、工资等级。传统的关系型数据库之中一定要存放大量的冗余数据,不合理。而又nosql数据库,可以直接在业务层里面将数据交给nosql数据库保存。按照指定的结构进行存储。

MongoDB数据库之中与Oracle数据库有如下的概念对应:

oracle:表  nosql:集合

oracle:行    nosql:文档

oracle:列         nosql:   成员

oracle: 主键:    nosql:object id(自动)

Node.js中一定要使用MongoDB,而node.js(基于JavaScript操作)在国内最成功的应用-taobao。

Mongodb:面向集合的存储过程,模式自由(无模式)。支持索引、支持短暂数据保留、填充、具备完整的数据库状态监控、基于BSON的应用。

Mongodb与mysql是一种互补的关系。

命令:

不设置端口号启动MongoDB服务:

mongod  --dbpath D:\MongoDB\db  表示要再这个目录保存所有的数据库文件的操作

设置端口号启动:

mongod  --dbpath D:\MongoDB\db --port=2700

如果通过程序访问数据库的话,一定要设置端口号。

使用mongo命令连接数据库(重新启动一个cmd)

mongo

范例:查询所有的数据库

show databases

此时,只存在一个local的本地数据库,不过这个数据库不使用。

在实际的开发中,在Mongodb中设置一些相应参数:端口号、是否启用用户验证、数据文件的位置等等。

在D:\MongoDB目录下,建立一个文件"mongodb.conf",

同时,建立一个保存日志信息的文件" mongodb.log"

重新启动mongodb的命令:

mongod -f d:\MongoDB\mongodb.conf

在Mongo数据库的基础操作:

1、使用mldn数据库:

use mldn

实际上这个时候并不会创建数据库,只有在数据库里面保存集合数据之后才能真正创建数据库。

2、创建一个集合

db.createCollection("emp")  创建一个emp集合

此时,利用show databases;可以看到创建的数据库即mldn数据库才会真正的存在。

3、但是很多时候如果按照以上代码的形式进行会觉得你不正常,正常是直接保存一个数据。

db.dept.insert({"deptno":10,"dname":"财务部","loc":"北京"});

4、查看所有集合的命令:show collections

可以看出dept的集合自动创建

5、查看emp标的数据

db.集合名称.find({若干条件})

从传统的数据表来看(集合就相当于表的结构),表的结构一旦定义就要按照其定义的内容来编写,但是MongoDB不一样,可以随意扩展数据。

6、可以随意增加数据

var deptData = {

"deptno":20,

"dname":"研发部",

"loc":"深圳",

"count":20,

"avg":8000.0

};

db.dept.insert(deptData)

此时dept集合的内容可以由用户随意去定义,完全不用考虑其它的结构,那么实际上就必须明确一点,在MongoDB数据库中是绝对不可能存在有查看集合结构的操作。

7、关于ID的问题

在MongoDB集合中的每一行记录都会自动的生成一个"_id“:" 数据组成是:时间戳+机器码+PID+计数器",这个ID的信息是MongoDB自己为用户服务的。

范例:查看单独的一个文档信息

db.dept.findOne();

8、范例:删除数据

db.dept.remove({"_id" : ObjectId("5624fc5bfddcd6e2428e9ed0")})

10、更新数据

var timData = {

"account":"tim",

"passwd":"123",

"studentid":525

};

db.dept.update({"_id" : ObjectId("5624fe1ffddcd6e2428e9ed1")},timData);

11、删除集合

语法:db.集合名称.drop()

db.dept.drop()

12、删除数据库(删除当前所在的数据库信息)

db.dropDatbase()

数据操作

CRUD:除了增加之外,其它的都很麻烦。

1、数据增加

使用:db.集合.insert() 可以实现数据的增加操作。

范例:增加一个简单的数据

db.infos.insert({"url":"www.mldn.cn"});

切换到mldn数据库:use mldn

范例:保存数组

db.infos.insert([

{"url":"www.mldn.cn"},

{"url1":"www.mldnjava.cn"}

]);

范例:保存10000个数据

for(var x = 0;x<10000;x++){

db.infos.insert({"url":"mldn-"+x});

}

如果数据保存很多的情况下,列表不会全部列出,只会列出部分内容。

2、数据查询

任何数据库中,数据的查询操作是最为麻烦的,而在MongoDB的数据库中有关系运算、逻辑运算、正则运算等等。

语法:db.集合名称.find({查询条件}[,{设置显示的字段}])

范例:最简单的用法是用find()函数完成查询:db.infos.find();

希望查询出url为:www.mldn.cn

db.infos.find({"url":"www.mldn.cn"});

对于设置的显示字段严格来说称为数据的投影操作,如果不需要显示的字段设置为”0“,而需要显示的字段设置为”1“。

范例:不显示ID

db.infos.find({"url":"www.mldn.cn"},{"_id":0,"url":1});

大部分的情况下,这种投影意义的查询意义不大,数据的查询可以使用”pretty()“函数进行漂亮显示。

范例:漂亮显示:

db.infos.find({"url":"www.mldn.cn"},{"_id":0,"url":1}).pretty();

数据列多的时候可以看出华丽的显示。

关系查询:

在MongoDB里面支持的关系查询操作:大于($gt)、小于($lt)、大于等于($gte)、小于等于($lte)、不等于($ne)、等于(key:value,$eq)。但是要想让这些操作可以正常使用,那么需要准备出一个数据集合。

范例:定义一个学生信息集合:

db.students.drop();

db.students.insert({"name":"张三","sex":"男","age":19,"score":89,"address":"北京"});

db.students.insert({"name":"李四","sex":"女","age":21,"score":59,"address":"广州"});

db.students.insert({"name":"王五","sex":"男","age":20,"score":99,"address":"天津"});

db.students.insert({"name":"赵六","sex":"女","age":19,"score":100,"address":"上海"});

db.students.insert({"name":"陈七","sex":"男","age":25,"score":20,"address":"深圳"});

db.students.insert({"name":"王八","sex":"男","age":19,"score":78,"address":"福州"});

范例:查询名字为张三的信息:

db.students.find({"name":"张三"}).pretty();

范例:查询性别是男的信息:

db.students.find({"sex":"男"}).pretty();

范例:查询年龄大于20岁:

db.students.find({"age":{"$gt":20}}).pretty();

范例:查询成绩大于等于60分:

db.students.find({"score":{"$gte":60}}).pretty();

范例:查询姓名不是王五的信息:

db.students.find({"name":{"$ne":"王五"}}).pretty();

此时与之前最大的区别就在于,在一个JSON结构里面需要定义其他的JSON结构,这种风格通过程序进行操作依然如此。

逻辑运算主要就是三种:与($and)、或($or)、非($not、$nor)。

范例:查询年龄在19~20岁的学生信息

db.student.find({"age":{"$gte":19,"$lte":20}}).pretty();

在进行逻辑运算的时候,"and”的连接是最容易的,因为只需要利用","分割若干个条件就可以了。

范例:查询年龄不是19岁。

db.student.find({"age":{"$ne":{"$gte":19}}});

范例:查询年龄大于19岁、或者成绩大于90分的学生信息:

db.students.find({"$or":[

{"age":{"$gt":19}},

{"score":{"$gt":90}};

] }).pretty();

针对于或的运算,可以实现一个求反的功能。

在这几个逻辑运算之中,与的连接最简单,而或的连接需要为数据设置数据的过滤条件。

求模

模的运算使用:“$mod” 语法:“{$mod:[数字,余数]}”

db.students.find({"age":{"$mod",[20,0]}}).pretty()

利用求模运算可以编写一些数学公式。

范围查询:

只要是数据库,必须存在有"$in"(在范围之中)、"$nin"(不在范围之中)

范例:查询姓名是"张三"、”李四"、“王五"的信息。

db.students.find({"name":{"$in":["张三","李四","王五"]}}).pretty();

在实际的工作之中,范围的操作很重要。

数组查询:

在mongodb是支持数组保存的,就需要对数组的数据进行匹配。

范例:保存一部分数组内容:

db.student.insert({"name":大神,"course":["语文","英语","数学"]});

此时的数据包含有数组的内容,而后需要针对数组数据进行判断,可以使用几个运算符:$alll、$size、$slice、$elemMatch

范例:查询同时参加语文和数学课程的学生:

现在两个数组内容都需要保存,所以使用"{"$all",[内容1,内容2,...]}"

db.students.find({"course":{"$all":["语文","数学"]}}).pretty();

现在显示所有信息包含语文和数学的内容,而如果差一个内容的不会显示。

虽然,$all 计算可以用于数组上,但是也可以用于一个数据的匹配上。

范例:查询学生地址是“海淀区"的信息

db.students.find({"address":{"$all":[海淀区]}}).pretty();

既然在集合里面保存的是数组信息,那么数组就可以利用索引操作,使用"key.index”的方式来定义索引。

范例:查询数组中第二个内容(index=1,索引下标从0开始)为数学的信息。

db.students.find({"course.1":"数学"}).pretty();

范例:要求查询出只参加两门课程的学生:(使用$size 来进行数量的控制)

db.students.find({"course":{"$size":2}})

在进行数据查询的时候,只要是内容符合条件,数组的内容就全部显示出来,但是现在希望可以控制数组返回的数量,那么可以使用$slice 进行控制。

范例:返回年龄为19岁,所有学生的信息,但是只显示两门参加课程。

db.students.find({"age":19},{"$course":{"$slice":2}}).pretty()

现在只取得前两门的信息,也可以设置取得后两门的信息,把上面的2设置为-2.

db.students.find({"age":19},{"$course":{"$slice":-2}}).pretty()

或者只是取得中间部分的信息:

db.students.find({"age":19},{"$course":{"$slice":[1,3]}}).pretty()

在此时设置的两个数据里面,第一个数据表示跳过的数据量,而第二个表示返回的数据量。

嵌套集合运算:

在MongoDB数据库里面每一个集合数据可以继续保存其它的集合数据,例如:有些学生需要保存家长信息。

范例:

此时给出的内容是嵌套的集合,而这种集合的数据的判断只能够通过"$elemMatch"完成

范例:查询出父母有人是局长的信息。

db.students.find("$and":[{"age":{"$gte":19}},{"parents":{"$elemMatch":{"job":"局长"}}}]).pretty();

由于这种查询的条件比较麻烦,所以尽可能不要搞这么复杂的数据结构组成。

判断某个字段是否存在:

使用“$exists”可以判断某个字段是否存在,如果设置为true表示存在,如果设置为false表示不存在.

范例:查询具有parents成员的数据

db.students.find({"parents":{"$exists":true}}).pretty();

范例:查询不具有course成员的数据:

db.students.find({"course":{"$exists":false}}).pretty();

可以利用此类查询来进行一些不需要的数据过滤,但是建议数据组成一致。

条件过滤

实际上习惯于传统关系型数据库开发的我们对于数据的筛选,可能首先想到的一定是where子句,所以在mogo里面也提供有"$where"。

范例:使用where进行数据查询

db.students.find({"$where":"this.age>20"}).pretty();

可以直接用:db.students.find("this.age>20").pretty();

对于“$where”是可以简化的,但是这类的操作是属于进行每一行的信息判断,实际上对于数据量较大的情况是不方便使用。实际上,以上的代码严格来讲是属于编写一个操作的函数。

db.students.find(function(){ return this.age>20; }).pretty();

以上只是查询了一个判断,如果要想实现多个条件的判断,那么就需要使用and连接。

db.students.find({"$and":[

{"$where":"this.age>19"}.

{"$where":"this.age<19"}

]}).pretty();

虽然这种形式的操作可以实现数据查询,但是最大的缺点是将MongDB里面保存的BSON数据变为JavaSript的语法结构,这样的方式不方便使用数据库的索引机制。

正则运算

如果要想实现模糊查询,那么必须使用正则表达式,而且正则表达式使用的语言Perl兼容的正则表达式的形式。如果要想实现正则使用,则按照如下的定义格式:

基础语法:{key:正则标记}

完整语法:{key:{"$regex":正则标记,"$options":选项}}

其中,对于options主要是设置正则的信息查询的标记。

"i":忽略字幕大小写

"m":多行查找

"x":空白字符串除了被转义的或在字符中意外的完全被忽略:

"s":匹配所有的字符(圆点、“.”),包括换行内容

需要注意的是,如果是直接使用(javascript)那么只能够使用i和m,而"x"和"s"必须使用"$regex"

范例:查询以"谷"开头的姓名

db.students.find({"name":/谷/}).pretty();

范例:查询姓名有字母a

db.students.find({"name":/a/i}).pretty(); 其中,i表示忽略大小写

上面的写法可以为:db.students.find("name":{"$regex":/a/i}).pretty();

如果要执行模糊查询的操作,严格来说只需要编写一个关键字。

正则操作之中,除了可以查询单个字段的内容之外,也可以查询数组数据。

范例:查询数组数据。

db.students.find("course":{"$regex":/语/}).pretty();

mongodB中的正则符号和之前java正则是有一些小小差别。不建议使用以前的一些标记,正则就用在模糊数据的查询上。

数据排序:

在mongoDB里面数据排序操作使用"sort()"函数,在进行排序的时候可以有两个顺序:升序(1)、降序(-1)

范例:数据排序

db.students.find().sort({"sort":-1}).pretty();

但是在进行排序的过程中,有一种方式称为自然排序,按照数据保存的先后顺序排序,使用"$natural"表示

范例:自然排序

db.students.find().sort({"$natural":-1}).pretty();

在MongoDB数据库里面排序的操作相比传统关系型数据库的设置要简单。

数据的分页显示:

在MongoDB里面的数据分页显示也是符合大数据要求的操作函数:

skip():表示跨过多少数据行。

limit(n):取出的数据行的个数限制。

范例:分页显示(第一页,skip(0),limit(5))

db.students.find().skip(0).limit(5).sort({"age":-1}).spretty();

范例:分页显示(第二页,skip(5),limit(5))

db.students.find().skip(5).limit(5).sort({"age":-1}).spretty();

这两个分页的控制操作,就是在以后只要有存在大数据的信息情况下都会使用它。

数据更新操作

对于MongoDB而言,数据的更新基本上是一件很麻烦的事情,如果在实际的工作中,真的具有此类的操作支持,那么最好的做法,在MongoDB里面对于数据的更新操作提供了两类函数:save()、update()。

函数的基本使用

如果要修改数据最直接的使用函数就是update()函数,但是这个函数的语法要求很麻烦。

语法:db.集合.update(更新条件,新的对象数据(更新操作符),upsert,multi)

-update:如果要更新的数据不存在,则增加一条新的内容(ture为增加、false为不增加)

-multi:表示是否只更新满足条件的第一行记录,如果设置为false,则只更新第一行记录,如果是true全更新。

以下是更新存在的数据:

范例:将年龄是19岁的人的成绩更新为100分(此时会返回多条数据)

db.students.update({"age":19},{"$set":{"score":100}},false,false); 选择只更新更新的第一条数据

db.students.update({"age":19},{"$set":{"score":100}},false,true); 所有满足条件的数据都更新

范例:更新不存在的数据

db.students.update({"age":30},{"$set":{"name":"不存在"}},true,false)

由于没有年龄是30岁的学生信息,所以此时相当于进行数据的创建。

那么除了update()函数之外,还提供有一个save()函数,这个函数的功能与更新不存在的内容相似。

范例:使用save()操作

db.students.save({"_id":ObjectId("5123145d2fde")},{"age":50})

save操作不好用,可以用update函数来使用。

修改器:

对于MongDB数据库而言,数据的修改会牵扯到内容的变更、结构的变更(包含有数组),所以在进行MongoDB设计的时候,就提供有一系列修改器的应用,那么之前使用的"$set"就是一个修改器的使用

1、$inc:主要针对于一个数字字段,增加某个数字字段的内容;

语法:{"$inc":{成员:内容}}

范例:将所有年龄为19岁的学生成绩一律减少30分,年龄加一岁

db.students.update({"age":19},{"$inc":{"score":-30,"age":1}},false,true);//全部执行,false,true

2、$set:进行内容的重新设置

语法:{"$set":{"成员":"新内容"}}

范例:将年龄是20岁的人的成绩修改为89分

db.students.update({"age":20},{"$set":{"score":19}})

3、$unset:删除某个成员的内容

语法:{"$unset":{"成员":1}}

范例:删除"张三"的年龄与成绩信息

db.students.update({"name":"张三"},{"$unset":{"age":1,"score":1}})

执行之后指定的成员内容就消失了。

4、$push:相当于将内容追加到指定的成员之中(基本上是数组)

语法:${"$push":{"成员":value}}

范例:向张三添加课程信息(此时张三信息里面没有course信息)

db.students.update({"name":"张三"},{"$push":{"course":["语文","数学"]}})

范例:向"谷大声-E"里面的课程追加一个"美术"

db.students.update({"name":"股大声-E"},{"$push":{"course":"美术"]}})

push就是进行数组数据的添加操作使用,如果没有数组则进行一个新的数组的创建,如果有则进行内容的追加。

5、$pushAll:与"$push"类似的,可以一次追加多个内容到数组里面:

语法:${"$pushAll":{成员:数组内容}}

范例:向"王五"的信息里面添加多个课程内容

db.students.update({"name":"王五"},{"$pushAll":{"course":["语文","数学"]}})

6、$addToSet:向数组里面添加一个新的内容,只有这个内容不存在的时候才会增加。

语法:{"$addToSet":{成员:内容}}

范例:向王五的信息增加新的内容

db.students.update({"name":"王五"},{"$addToSet":{"course":"跳舞"}})

此时会判断要增加的内容在数组里面是否已经存在了,如果不存在则追加内容,如果存在,则不增加内容。

7、$pop:删除数组内的数据:

语法:{"$pop":{成员:内容}},内容如果设置为-1表示删除第一个,1表示删除最后一个

范例:删除王五的一个课程

db.students.update({"name":"王五"},{"$pop":{"course":"-1"}})

范例:删除王五的最后一个课程:

db.students.update({"name":"王五"},{"$pop":{"course":"1"}})

8、$pull:从数组内删除一个指定内容的数据

语法:{"$pull",{成员:数据}} 进行数据比对,如果是此数据则进行删除

范例:删除王五内的跳舞的课程,如果存在就删除

db.students.update({"name":"王五"},{"$pull":{"course":"跳舞"}})

9、$pullAll:一次性删除多个内容

语法:{"$pull":{成员:[数据1,数据2]}}

范例:删除”顾大神-a“的二门课程

db.students.update({"name":"股大声"},{"$pullAll":{"course":["跳舞","音乐"]}})

10、$rename:为成员名称重命名

语法:{"$rename":{旧的成员名称:新的成员名称}}

范例:将"张三"name成员名称修改为"姓名"

db.students.update({"name":"王五"},{"$rename":{"name":"姓名"}})

在整个的MongoDB数据库里面,提供的修改器的支持很到位。

删除数据:

在MongoDB里面数据的删除实际上并不复杂,只需要使用"remove()"函数就可以了。

但是,整个函数是有两个可选项。1、删除条件:满足条件的数据被删除 2、是否只删除一个数据,如果设置为true或者是1表示只删除一个。

范例:清空info集合中的内容。

db.infos.remove({});

范例:删除所有姓名里面带有“谷”的信息。

db.students.remove({"name":/谷/})

范例:删除姓名带有"高"的信息,要求只删除一个

db.students.remove({"name":/高/},true)

删除操作里面依然需要使用限定查询的相关操作内容。

游标:

所谓的游标就是指的数据可以进行一行行的进行操作,非常类似于ResultSet数据处理。在MongoDB数据里面对于游标的控制非常简单,只需要使用find()函数就可以返回游标了。对于返回的游标如果要进行操作,则可以通过两个函数:一个是是否有下一行数据:hasNext(),另一个是取出当前数据next();

var cursor = db.students.find();

cursor.hasNext()

cursor.next();

以上是游标的操作形式,但是实际上并不可能这么去用,因为必须利用循环才能输出内容。

相当于每一个数据都单独拿出来逐行的控制。当我们游标数据取出来的时候,实际上每行数据返回的都是Object型的内容,那么如果需要数据按照json的形式出现,可以使用printjson()函数完成。

在所有的已知数据里,MongoDB的游标操作是最简单的,最直观的。

索引

在任何的数据库之中,索引都是一种提升数据库检索性能的手段,这一点在MongoDB数据库之中同样是存在的,在MongoDB数据库之中,依然会存在两种的索引的创建:一种是自动创建的;另一种是手工创建。

范例:重新准备一个新的简单集合

此时,我们在students集合之上并没有设置任何的索引,那么下面通过getIndexes()函数来观察在students集合已经存在索引内容。

范例:查询默认状态下的students集合的索引内容。

db.students.getIndexes();

想创建自己的索引,如下:

索引创建:db.集合名称.ensureIndex({列:1})

-设置的1表示索引将按照升序的方式进行排列,如果使用降序设置"-1"

范例:创建一个索引,在age字段上设置一个降序索引

db.students.ensureIndexes({"age":-1})

此时并没有设置索引的名字,所以名字是自动命名的。命名规范:“字段名称_索引的排序"

范例:针对于当前的age字段上的索引做一个分析

db.students.find("age":19).explain();

此时的查询使用了索引的技术,但是下面再来观察一个查询,不使用索引字段。

范例:针对score字段上设置查询

db.students.find({"score":{"$gt":60}}).explain();

此时在score上的字段并没有设置索引,所以当前的索引形式就变为了全集合扫描的模式。

但是,如果说现在年龄和成绩一起执行查询。

db.students.find({"$or":[{"age":{"$gt":19}},{"score":{"$gt":60}}]}).explain();

这个时候虽然age字段上存在有索引,但是由于score字段上没有索引,所以依然使用的是全表扫描操作,所以此时,为了解决这个问题,可以使用一个符合索引。

db.students.ensureIndex({"age":-1,"score":-1},{"name":"age_-1_score_-1"})

范例:默认使用索引

db.students.find({"age":19,"score":89}).explain()

但是如果换到了条件之中:

db.students.find({"$or":[{"age":{"$gt":19},{"score":{"$gt":60}}}]}).explain();

但是发现并没有使用索引,所以如果这个时候看能够强制使用一次索引。hint()函数为强制使用一次索引操作。

范例:强制使用索引

db.students.find({"$or":[{"age":{"$gt":19},{"score":{"$gt":60}}}]}).hint({"age":-1,"score":-1}).explain();

正常来讲,这个代码根本就不可能调用默认的索引执行,可使用hint()函数,告诉MongDB必须使用一次索引,由于此时在age和score两个字段已经设设置了符合索引,那么现在 的复合索引。

但是在一个集合里面设置了过多的索引,实际上会导致性能下降,那么就可以删除索引。

范例:删除一个索引

db.students.dropIndex({"age":-1,"score":-1})

可是如果一个一个删除索引,也会很麻烦,所以提供有删除全部索引的操作。

范例:删除全部索引。

db.students.dropIndex()

所谓的删除全部索引,就是非"_id"的索引,所有的自定义索引。

唯一索引:

唯一索引的主要目的是用在某一个字段上,使该字段的内容不重复。

范例:创建一个唯一索引

db.students.ensureIndex({"name":1},{"unique":true})

在name字段上的内容绝对不允许重复。

范例:在students集合里面增加重复的数据。

此时除了,name字段上的内容之外,发现所有的数据都不一样,但是由于在name字段上设置了唯一索引,所以整个程序里面,如果增加了重复内容,会出现以下的错误信息。

过期索引:

在一些程序点上回出现若干秒之后信息被删除的情况,例如:手机的信息验证码,那么在MongoDB里面可以轻松的实现过期索引,但是这个时间往往不怎么准确。

范例:设置过期索引

db.phones.ensureIndex({"time":1},{expireAfterSeconds:10})

设置索引在10秒后过期

等到10秒之后(永远不会那么准确)所保存的数据就会消失。这个操纵在进行一些临时数据保存的时候非常有帮助,最早如果没有MongoDB,而是使用最简单的关系型数据库进行开发这个过程是非常麻烦的。

范例:在一个叫做phone集合里面设置过期索引

如果要想实现过期索引,需要保存一个时间信息。

db.phones.insert({"tel":"110","code":"110","time":new Date()})

全文索引

在一些信息管理平台上经常要进行信息模糊查询,最早的时候是利用了某个字段上实现的模糊查询,但是这个时候返回的信息,并不会很准确,因为只能够查询A字段或者是B字段,而在MongoDB里面实现了非常简单的全文检索。

范例:定义一个新的集合:

db.news.insert({"titel":"mldn java","content":"gyh"})

范例:设置全文检索

db.news.ensureIndex({"title":"text","content":"text"})

范例:实现数据的模糊查询

如果要想表示出全文检索,则使用"$text"判断符,而要想进行数据查询则使用"$search"运算符:

-查询指定的关键字;{"$serach":"查询关键字"}

-查询多个关键字(或关系):{"$search":"查询关键字 查询关键字 ..."}

-查询多个关键字(与关系){"$search":"\"查询关键字\""}

-查询多个关键字(排除某一个):{"$search":" "}

范例:查询单个内容

db.news.find("{"$text":{"$search":"gyh"}}")

范例:包含有"gry"与"sfq"的信息

db.news.find("{"$text":{"$search":"gry sfq"}}")

范例:同时包含有"mldn" 与 "lxh"的内容

db.news.find({"$text":{"$search":"\"mldn\" \"lxh\""}})

范例:包含有"mldn",但是没有"gyh"的信息。

db.news.find("$text":{"$serach":"\"mldn\" \"lxh\" -gyh"})

但是在进行全文检索操作的时候,还可以使用相似度的打分来判断检索成果。

范例:为结果打分

db.news.find({"$text":{"$search":"gyh"}},{"score":{"$meta":"textScore"}}).sort({"score":{"score":{"$meta":"textScore"}})

按照打分的成绩进行排列可以实现更加准确的信息搜索。

但是在这里面还有一个小问题,如果一个集合的字段太多了,那么每一个字段都分别设置全文检索麻烦点。所以简单一些,可以为所有字段设置全文检索。

范例:为所有字段设置全文索引

db.news.ensureIndex({"$**":"text"})

这是一种最简单的设置全文索引的方式,但是尽可能不用,速度慢。

地理信息索引

地理信息索引分为两类:2D平面索引,另外就是2DSphere球面索引。在2D索引里面基本上能够保存的信息都是坐标,而且坐标保存的就是经纬度坐标。

范例:定义一个商铺的集合

db.shop.insert({loc:[10,11]})

范例:为shop集合定义2D索引

db.shop.ensureIndex({"loc":"2d"})

这个时候shop集合就可以实现坐标位置的查询,而要进行查询有两种查询方式:

-1:"$near"查询,查询距离某个点最近的坐标点

-2:"$geoWithin"查询:查询某个形状内的点

范例:假设我现在的坐标是[11,11]

db.shop.find({"loc":{"$near":[11,11]}})

但是,如果执行以上的查询,实际上会将集合里面的额前100个点的信息都返回来了,可是太远了,设置了一个距离范围--5个点内。

范例:设置查询的距离范围

db.shop.find({"loc":{"$near":[11,11],"$maxDistance":5}})

但是,我们需要注意一点,在2D的索引里面虽然支持最大距离,但是不支持最小距离。

但是,也可以设置一个查询的范围,使用"$geoWithin"查询,可以设置以下几种范围:

-1、矩形范围($box) {"$box":[[x1,y1],[x2,y2]]}

-2、圆形范围($centor):{"$center":[[x1,y1],r]}

-3、多边形($polygon):{"$polygon":[[x1,y1],[x2,y2],[x3,y3]]}

范例:查询矩形

db.shop.find({"loc":{"$geoWithin":[[9,9],[11,11]]}})

范例:查询圆形

db.shop.find({"loc":{"$geoWithin":[[9,9],2]}})

在MongoDB数据库里面,除了一些支持的操作函数之外,还有一个重要的命令:runCommand(),这个函数可以执行特定的MongoDB命令。

范例:利用runCommand()实现信息查询

db.runCommand({"geoNear":"shop",near:[10,10],maxDistance:5,num:2})

这类的命令可以说是MongoDB之中最为基础的命令。

聚合函数:

MongoDB产生的背景是在大数据的环境下,实际上大数据就是进行信息的收集汇总。那么必须存在有信息的统计操作,而这样的统计操作称为聚合(直白:分组统计就是一种聚合操作)。

取得集合的数据量

对于集合的数据量而言,在MongoDB里面直接使用count()函数就可以完成。

范例:统计students表中的数据量

db.students.count();

范例:模糊查询

db.students.count({"name":/张/i})

在信息查询的时候,不设置条件永远要比设置条件的查询快很多。也就是说,在之前的代码编写里面不管是查询全部还是模糊查询,实际最终都使用模糊查询的一种(没有设置关键字)。

消除重复数据:

在学习SQL的时候,对于重复的数据可以使用"DISTINCT",那么这一操作在MongoDB之中依然支持。

范例:查询所有name的信息(没有重复)。

-本次的操作没有直接的函数支持,只能怪利用runCommand()函数。

db.runCommand({"distinct":"students","key":"name"})

此时,实现了对于name数据重复值得筛选。

group操作

使用"group"操作可以实现数据的分组操作,在MongoDB里面会将集合指定的Key的不同进行分组操作,并且每一个组都会产生我们处理的文档结果。

范例:查询所有年龄大于等于19岁的学生信息,并且按照年龄分组。

db.runCommand({"group":{"ns":"students",

"key":{"age":true},

"initial":{"count":0},

"condition":{"age":{"$gte":19}},

"$reduce":function(doc,prev){

prev.count++;

}

}});

以上的操作代码里面实现的就属于一种MapReduce,但是这样只是根据传统的数据库设计思路操作实现所谓的分组操作。但是这个分组操作的最终结果是有限的。

MapReduce

MapReduce是整个大数据的精髓所在(实际中别用),所谓的MapReduce就是分为两步处理数据:

-Map:将数据分别取出

-Reduce:负责数据的最后处理。

可是要想在MongoDB里面实现MapReduce处理,那么复杂度是相当高的。

范例:建立一组雇员数据

db.emps.insert({"name":"张三","age":30,"sex":"男","job":"CLERK","salary":1000})

使用MapReduce操作会将处理结果保存在一个单独的集合里面,而最终的处理效果如下:

范例:按照职位分组,取得每个职位的人名

-    编写分组的定义:

var jobMapFun = function()

{

emit(this.job,this.name);//按照job分组,取出name

};

第一组:{key:"CLERK",values:[姓名,姓名,,,,]}

-编写Reduce操作:

var jobReduceFun= function(key,values){

return{"job":key,"names":values};

}

var jobFinalizeFun = function(key,values){

if(key == "PRESIDENT"){

return{"job":key,"names":value,"info":"公司的老大"}

}

return{"job":key,"names":values};

}

-进行操作的整合:

db.runCommand({"mapreduce":"emps","map":jobMapFun,"reduce":jobReduceFun,"out":"t_job_emp",”“finalize":jobFinalizeFun})

现在执行之后,所有的处理结果都保存在"t_job_temp"集合里面。

范例:统计出个性别的人数、平均工资、最低工资、雇员姓名

var sexMapFun = function(){

//定义好分组的条件,以及每个集合要取出的内容

emit(this.sex,{"ccount":1,"cavg":this.salary,"cmax":this.salary,"cmin":this.salary,"cname":this.name});//emit表示分组处理函数

}

var sexReducnFun = function(key,values){

var total =0;//统计

var sum =0;//计算总工资

var max = values[0].cmax; //第一个数据是最高工资

var min = values[0].cmin;//第一个数据是最低工资

var names = new Array();//定义数组内容

for(var x in values){//表示循环取出里面的数据

total+= values[x].ccount;//特殊增加

sum+=values[x].csal;//就可以循环取出所有的工资,并且累加

if(max<values[x].cmax){//不是最高工资

max = values[x].cmax;

}

if(min>values[x].cmin){//不是最低工资

min = values[x].cmin;

}

name[x] = values[x].cname; //保存姓名

}

var avg = (sum/total).toFixed(2);//设置两位小数

//返回数据的处理结果

return("count":total,"avg":avg,"sum":sum,"max":max,"min":min,"names":names);

};

db.runCommand({

"mapreduce”:"emps",

"map":sexMapFun,

"reduce":sexReduceFun,

"out","t_sex_emp"

});

虽然大数据的时代,提供有最强悍的MapReduce,但是从现实的开发中,真的不可能实现起来,很耗时。但是该功能可用定时任务来定期处理数据结果。

聚合框架:

MapReduce功能强大,但是它的复杂度和功能一样强大,那么我们说很多时候,我们需要MapReduce功能,但是又不想把代码写的太复杂,所以从Mongo 2.x版本之后引入了聚合框架并且提供了聚合函数:aggregate()。

group操作

group主要进行分组的数据操作:

范例:实现聚合查询的功能--求出每个职位的雇员人数

db.emps.aggregate(["$group":{"_id":"$job","job_count":{"$sum":1}}]);

这样的操作,更加符合传统的group by子句的操作使用。

范例:求出每个职位的总工资

db.emps.aggregate(["$group":{"_id":"$job","job_count":{"$sum":"$salary"}}]);

在整个聚合框架里面如果要使用每行的数据使用:"$字段名称"

范例:计算出每个职位的平均工资

db.emps.aggregate(["$group":{"_id":"$job","job_sal":{"$sum":"$salary"},"job_avg":{"$avg":"$salary"}}]);

范例:求出最高与最低工资

db.emps.aggregate(["$group":{"_id":"$job","max_sal":{"$max":"$salary"},"min_sal":{"$min":"$salary"}}]);

以上的几个与SQL类似的操作计算成功的实现了。

范例:计算出每个职位的工资数据(数组显示)

db.emps.aggregate([{

"$group":{

"id":"$job",

"sal_data":{"$push":"$salary"}

}

}]);

范例:求出每个职位的人员:

db.emps.aggregate([{

"$group":{

"_id":"$job",

"sal_data":{"$push":"$name"}

}

}]);

以上使用"$push"的确可以将使用的数据变为数组进行保存,但是有一个问题出现了,重复的内容也会进行保存。在MongoDB里面提供有取消重复的设置。

范例:取消重复的数据

db.emps.aggregate([{

"$group":{

"id":"$job",

"addToSet":{"$push":"$name"}

}

}]);

默认情况下,是将所有的数据都保存进去,但是希望可以保存第一个和最后一个的数据。

范例:保存第一个内容

db.emps.aggregate([{

"$group":{

"id":"$job",

"addToSet":{"$first":"$name"}

}

}]);

范例:保存最后一个内容

db.emps.aggregate([{

"$group":{

"id":"$job",

"addToSet":{"$last":"$name"}

}

}]);

虽然可以实现分组处理,但是有一点需要注意,所有的分组数据是无序的,并且都是在内存之中完成,所以不可能支持大数据量。

$project

可以利用"$project"来显示数据列的显示规则,那么可以执行的规则如下:

-普通列({成员:1|true}):表示要显示的内容

-"_id"列({"_id":0|false}):表示"_id"列的显示是否显示

-条件过滤列({成员:表达式}):满足表达式之后的数据可以进行显示

范例:只显示name、job列

db.emps.aggregate({"$project":{"_id":0,"name":1}})

此时,只有设置进去的列才可以被显示出来,而其他的列不能够被显示出来。实际上这就属于数据库的投影机制。

实际上在进行数据投影的过程里面也支持四则运算:加法("$add")、减法("$subtract")、乘法("$multiply")、除法("$divide")、求模("$mod")

范例:观察四则运算

db.emps.aggregate([{"$project":{

"_id":0,

"name":1

"job":1,

"salary":{"年薪":{"$multiply":["$salary",12]}}

}}])

除了四则运算之外,也支持如下的各种运算fu :

-关系运算:大小比较("$cmp")、等于("$eq")、大于("$gt")、大于等于("$gte")、小于“$lt”、小于等于"$lte"、不等于"$ne"、判断NULL("$ifNull"),这些操作返回的结果都是布尔型数据。

-逻辑运算:与"$and"、或"$or"、非"$not"

-字符串操作:连接"$concat"、截取"$substr"、转小写"$ToLower"、转大写"$ToUpper"、不区分大小写比较"$strcasecmp"

范例:找出所有工资大于等于2000的雇员的姓名、年龄、工资

db.emps.aggregate([{"$project":{

"_id":0,

"name":1,

"job":1,

"工资":"$salary",

"salary":{"$gte":["$salary",2000]}

}}])

范例:查询职位是manager的信息

-MongoDB的数据是区分大小写的:

db.emps.aggregate([{"$project":{

"_id":0,

"name":1,

"职位":"$job",

"工资":"$salary",

"job":{"$eq":["$job",{"$toUpper":"manager"}]}

}}])

范例:使用字符串截取

db.emps.aggregate([{"$project":{

"_id":0,

"name":1,

"职位":"$job",

"job":{"前面三位":{"$substr":["$job",0,3]}}

}}])

利用"$project"实现的投影操作功能相当强大,所有可以出现的操作几乎都能够使用。

$sort

使用"$sort"可以实现排序,设置1表示升序,设置-1表示降序。

范例:实现排序

db.emps.aggregate([{"sort":{"age":-1,"salary":1}}])

分页处理:$limit $skip

$limit:负责数据的取出个数

$skip:数据的跨过个数

$unwind

在查询数据的时候经常会返回数组信息,但是数组并不方便信息的浏览,所以提供有"$unwind"可以将数组数据变为独立的字符串内容。

$geoNear

使用"$geoNear"可以得到附近的坐标点

$out

"$out":利用此操作可以将查询结果输出到指定的集合里面。

范例:将投影的结果输出到集合之中

db.emps.aggregate([{

"$project":{"_id":0,"name":1,"salary":1,"job":1}},

{"$out":"emp_infos"}

])

这类的操作相当于实现最早的数据表的复制操作。

固定集合:

所谓的固定集合指的是规定集合大小,如果要保存的内容已经操作了集合的长度,那么会采用LRU的算法(最近最少使用原则)将最早的数据移出,从而保存新的数据。

默认情况下一个集合可以使用createCollection()函数创建,或者使用增加数据后自动创建,如果使用固定集合,必须明确的创建一个空集合。

范例:创建一个空集合(固定集合)

db.createCollection("depts",{"capped":true,"size":1024,"max":5})

其中,"capped":为一个固定集合,而"size:1024"指的是集合所占的空间容量(字节),"max:5"表示最多只能有5条记录文档。

范例:向集合里面保存5条数据。

db.depts.insert({"deptno":10,"dename":"财务部-A","loc":"北京"})

db.depts.insert({"deptno":11,"dename":"财务部-A","loc":"北京"})

db.depts.insert({"deptno":12,"dename":"财务部-A","loc":"北京"})

db.depts.insert({"deptno":13,"dename":"财务部-A","loc":"北京"})

db.depts.insert({"deptno":14,"dename":"财务部-A","loc":"北京"})

此时已经达到集合的上限,那么继续保存新的内容。

db.depts.insert({"deptno":15,"dename":"财务部-F","loc":"北京"})

此时,最早保留的数据已经消失了。实际上,这种操作跟缓存机制非常相似的,例如:在百度上经常会出现搜索的关键词,这些词都是会被不断替换的。

GridFS

在MongoDB里面支持大数据的存储(例如:图片、音乐、各种二进制数据),但是这个做法需要用户自己处理了。使用"mongofiles"完成。

1、利用命令行进入到所在的路径下

2、将文件保存到文件库之中:

mongofiles --port=27001 put photo.tif

此时,会向数据库里面写入要保存的二进制数据。

3、查看保存的文件

mongofiles --port=27001 list

4、在MongoDB里面有fs系统的集合,这个集合默认保存在test集合的数据库中

use test;

db.fs.files.find();

5、删除文件

mongofiles --prot=27001 delete photo.tif

等于在MongoDB里面支持二进制数据的保存,但是存在的意义不大。

时间: 2024-10-28 22:08:12

MongoDB基本语法的相关文章

MongoDB常用语法

1 MongoVUE用法 1.1 模糊查询 头匹配: {"title":new RegExp("^各地发起纪念周总理")} 任意位置匹配: {"published":{$gte: "2013-05-01", $lt: "2013-06-10"}, "title":new RegExp(".*北京.*")} 1.2 时间段查询 {"published"

mongodb c#语法基础

这里采用的是mongoDB官网推荐使用.net驱动: http://mongodb.github.io/mongo-csharp-driver/2.0/getting_started/quick_tour/ 有关于MongoDB的安装读者可以参考其他的博客,对于基本的学习来说并不需要进行过多的配置. 创建连接 这一步骤跟ADO.NET连接到数据库的步骤是一样的,ADO.NET是利用SqlConnection连接数据库,而MongoDB则使用MongoClient连接,并在构造函数中将连接字符传递

mongodb基础语法

Mongodb与关系型数据库最大的区别就是无约束, 既无字段(外键等)约束, 也没有数据类型约束, 以json存储 安装 启动Mongodb(默认在c盘找 data/db/文件夹) 服务端: mongod --dbpath "制定数据库目录" 默认端口 27017 客户端: mongo 常用命令: show dbs 查看所有存在磁盘上的数据库 show tables 查看当前数据库存在磁盘上的表(collections) use db 创建(不存在这个名字) 或者 切换数据库 db 当

MongoDB学习之安装及基本语法

参考:http://www.cnblogs.com/lzrabbit/p/3682510.html 参考:http://blog.csdn.net/qqiabc521/article/details/6325203 1)mongodb安装为windows服务 官网下载并解压后 mongod --dbpath D:\MongoDB\data --install mongod --dbpath D:\MongoDB\data --logpath=D:\MongoDB\logs\mongodb.log

MongoDB基本shell操作

---------------------MongoDB基本操作--------------------- 1.MongoDB创建数据库 use 数据库名:切换到指定的数据库中,在插入第一个条数据的时候,创建对应的数据库. show dbs:显示所有的数据库名. db:查看当前数据库的名称. show collections:查看当前db所有的collections. db.集合名.insert({"name":"python"}):为指定的集合添加一条数据. 2.

Nodejs学习笔记(十)--- 与MongoDB的交互(mongodb/node-mongodb-native)、MongoDB入门

目录 简介 MongoDB安装(windows) MongoDB基本语法和操作入门(mongo.exe客户端操作) 库操作 插入 查询 修改 删除 存储过程 nodejs操作MongoDB 插入 查询 修改 删除 调用存储过程 写在之后... 简介 MongoDB 开源,高性能的NoSQL数据库:支持索引.集群.复制和故障转移.各种语言的驱动程序:高伸缩性: NoSQL毕竟还处于发展阶段,也有说它的各种问题的:http://coolshell.cn/articles/5826.html  官网地

MongoDB 基础(三)mongodb 中的索引使用

MongoDB中的索引和其他数据库索引类似,也是使用B-Tree结构.MongoDB的索引是在collection级别上的,并且支持在任何列或者集合内的文档的子列中创建索引. 下面是官方给出的一个使用索引查询和排序的一个结构图. 所有的MongoDB集合默认都有一个唯一索引在字段"_id"上,如果应用程序没有为 "_id"列定义一个值,MongoDB将创建一个带有ObjectId值的列.(ObjectId是基于 时间.计算机ID.进程ID.本地进程计数器 生成的)

深入浅出MongoDB应用实战开发视频教程

下载地址:http://pan.baidu.com/s/1c1rsW1q 密码:mjsl 课程大纲: MongoDB基础: 第1讲.nosql与MongoDB(nosql兴起的背景.各种nosql数据库介绍,MongoDB的特点) 第2讲.MongoDB安装配置 (MongoDB安装使用,基本系统管理的技巧,web控制台使用) 第3讲.MongoDB shell详解 (介绍MongoDB shell使用及命令,备份恢复.数据导入导出) 第4讲.MongoDB文档.集合.数据库的概念(介绍文档.集

nodejs笔记--与MongoDB的交互篇(七)

原文地址:http://www.cnblogs.com/zhongweiv/p/node_mongodb.html 目录 简介 MongoDB安装(windows) MongoDB基本语法和操作入门(mongo.exe客户端操作) 库操作 插入 查询 修改 删除 存储过程 nodejs操作MongoDB 插入 查询 修改 删除 调用存储过程 写在之后... 简介 MongoDB 开源,高性能的NoSQL数据库:支持索引.集群.复制和故障转移.各种语言的驱动程序:高伸缩性: NoSQL毕竟还处于发