MongoDB
来源:互联网 发布:解析json 编辑:程序博客网 时间:2024/06/18 12:49
1传统数据库技术回顾
数据库就是存储数据的,那么存储数据就用txt就行了啊,为什么要有数据库?
理由之1: 数据库有行、列的概念,数据有关系,数据不是散的。
老牌数据库,比如MySQL、SQL Server、Oracle、Access。这些数据库,我们管他们叫做结构型数据库。为什么?因为每个表中,都有明确的字段,每行记录,都有这些字段。不能有的行有,有的行没有。
理由之2:数据库能够提供非常方便的接口,让增删改查操作变得简单
我们的老牌数据库,都无一例外的使用SQL语言,管理数据库。
SQL就是structure query language。
比如,查询所有女生: SELECT * FROM step1 WHERE xingbie = ‘女’;
再比如,查询所有女生,并且年龄20~24之间,且在北京:
SELECT * FROM step1 WHERE xingbie = '女' AND nianling < 24 AND nianling >= 20 AND xianzaisuozaidi = '北京';
理由之三:数据库不能自己玩儿,要给向PHP、.net、jsp等语言提供接口。
用php这些语言,能够向数据库之中增删改查。
老牌数据库,都是结构型数据库,现在出了什么问题?
比如,我们现在想往一个已经有1000条数据的数据库中增加一个字段“高中信息”。
之前已经存在的数据,实际上不需要增加这个字段。因为这些用户已经填写完毕表单了,不需要再手机高中信息了。我们的意图就是在今后注册的用户,需要填写高中信息。但是,我们刚才说了,所谓的字段,是表的一个结构。所有的行都必须拥有,不能有的行有这个字段,有的行没有这个字段。
可想而知,大数据时代,数据库中有100万条数据都算少的。我们如果要动字段,时间太长。
所以,字段这个东西,太不灵活。
数据不灵活。一个字段,需要是同样类型的数据。不能一行记录是文本,一行记录是数字。
非结构型数据库NoSQL应运而生。
NoSQL是个怪胎,无法挑战老牌数据库,但是在大数据时代有自己的意义。
2 NoSQL
NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是SQL”,是一项全新的数据库革命性运动,早期就有人提出,发展至2009年趋势越发高涨。NoSQL的拥护者们提倡运用非关系型的数据存储,相对于铺天盖地的关系型数据库运用,这一概念无疑是一种全新的思维的注入。
非结构型数据库。没有行、列的概念。用JSON来存储数据。
集合就相当于“表”,文档就相当于“行”。
1.数据库 DataBase
● 数据库中存储众多集合。
● 数据库最终会变为文件系统里面的文件,而数据库名字就是相应的文件名,所以数据库的命名,应该遵守操作系统的文件名命名规范。
● 数据库命名不能是admin、local、config
2.集合 Collections
集合就是一组文档,相当于“表”。
集合中可以存储完全不同结构的文档。
3.文档
NoSQL中,最小的“数据条目”,不是“行”,而是“文档”。
文档就是键值对的一个集合,实际上表达方式和JSON一样。
文档就是JSON,但是要比JSON多了一些限制:
● 每个文档必须有一个特殊的键 _id ,这个键在集合中必须是唯一的。
● 文档中的所有键不能重复;大小写不同的键,视为不同的键。
● 文档中键的命名,不能含有.和$,其他不限,甚至可以用中文命名、阿拉伯数字。
● 文档中值的类型,比JavaScript中多了一些,比如日期、ObjectId()、正则表达式。
● 文档给程序员看的时候,是JSON的表示模式,但是实际存储的时候,是BSON方式,即用二级制方式存储。
4.总结NoSQL的特点和优势
我们总结NoSQL数据库在以下的这几种情况下比较适用:
1、数据模型比较简单;
2、需要灵活性更强的IT系统;
3、对数据库性能要求较高;
4、不需要高度的数据一致性;
我们看,有些系统,特别需要筛选。比如,筛选出所有女生大于20岁的。那么SQL型数据库,非常擅长!因为它有行、列的概念。
但是,有些系统,真的不需要进行那么多的筛选,比如站内信。站内信只需要存储就好了。不需要筛选。那么NoSQL的。
NoSQL不是银弹,没有资格挑战老牌数据库,还是特定情况下,是适合的。
3 MongoDB
1. MongoDB基本安装
官网:https://www.mongodb.com/
手册:https://docs.mongodb.org/manual/
win7系统需要安装补丁,KB2731284。
此时,我们看一下装好的文件夹:
C:\Program Files\MongoDB\Server\3.0\bin 加入到系统的path环境变量中(这样就可以全局使用MongoDB命令了)
2. MongoDB基本使用
那么我们就能在系统的任何盘符,使用mongo命令了:
使用数据库: mongo
开机: mongod
导入数据: mongoimport
1.先开一个CMD:
开机命令:
–dbpath就是选择数据库文档所在的文件夹。(c:\mongo是自己在c盘下建立mongo,也就是说我们要自己创建数据库文档所在的文件夹)
也就是说,mongoDB中,真的有物理文件,对应一个个数据库。U盘可以拷走。
一定要保持,开机这个CMD不能动了,不能关,不能ctrl+c。 一旦这个cmd有问题了,数据库就自动关闭了。
2.再开一个CMD:
输入
那么,运行环境就是mongo语法了。
列出所有数据库:
show dbs
使用某个数据库
use 【数据库名字】
如果想新建数据库,也是use。use一个不存在的,就是新建。(例如新建use hcd)
查看当前所在数据库
db
插入数据:
student就是所谓的集合。集合中存储着很多json。
student是第一次使用,集合将自动创建。
3.实例:
1号cmd
开机:
mongod --dbpath D:\mongo
2号cmd
mongo //连接show dbs //查看数据库use hcd //新建hcd (如果你不插入数据,hcd的数据库是不会被创建的)switched to db hcddb //查看当前数据库hcddb.student.insert({"name":"hcd"}); //数据库中新建student集合,并插入数据WriteResult({ "nInserted" : 1 })show collections //显示所有的集合studentsystem.indexesdb.student.find() //查看student集合的数据{ "_id" : ObjectId("599c2fc210caa6deb9584e47"), "name" : "hcd" }
3. MongoDB视图软件 MongoVUE的使用
安装后打开
1.创建连接(要确定本地的mongoDB已经打开)
首先现按 +号(没有直接弹出框的话点左上角Connect按钮) 然后弹出窗口,name:自己想起的连接数据库的名字(不是数据库的名字),Server:127.0.0.1(本地服务地址),然后点击Save按钮
2.观察
假如:我们创建连接名字为first,数据库名字为test,集合名字books,集合中有两个文档,
按钮Tree View Table View Text View为查看文档的方式
4 MongoDB数据库的使用
(注意:这里是cmd的命令行方式,不用特别记住,还有Node方式)
可以查看手册https://docs.mongodb.org/manual/
1 插入数据
插入数据,随着数据的插入,数据库创建成功了,集合也创建成功了。
db.student.insert({"name":"xiaoming"});
我们不可能一条一条的insert。所以,我们希望用sublime在外部写好数据库的形式,然后导入数据库:
注意:mongoimport和mongo是同级的,不能在连接mongo后再执行:mongoimport命令
mongoimport --db test --collection restaurants --drop --file primer-dataset.json
-db test 想往哪个数据库里面导入
–collection restaurants 想往哪个集合中导入
–drop 把集合清空
–file primer-dataset.json 哪个文件
这样,我们就能用sublime创建一个json文件,然后用mongoimport命令导入,这样学习数据库非常方便。
例如:
mongoimport --db hcd --collection student --drop /c/Users/Administrator/Desktop/a.json
将数据存放在hcd数据库中的student的集合中,然后将json拖入命令工具中就行了
2 查找数据
查找数据,用find。find中没有参数,那么将列出这个集合的所有文档:
db.restaurants.find() //(列出restaurants集合的所有数据)
精确匹配:
db.student.find({"score.shuxue":70}); // {a:{b:‘c’}} 就用“a.b”:c表示11
多个条件:
db.student.find({"score.shuxue":70 , "age":12})
大于条件:
db.student.find({"score.yuwen":{$gt:50}});
寻找所有年龄是9岁,或者11岁的学生
db.student.find({$or:[{"age":9},{"age":11}]});
查找完毕之后,打点调用sort,表示升降排序。
db.restaurants.find().sort( { "borough": 1, "address.zipcode":-1 } )//这里面表示先按照borough来升序排列,如果borough相同,则按照address.zipcode降序排列
3 修改数据
修改里面还有查询条件。你要该谁,要告诉mongo。
默认情况下更改第一个匹配的元素
查找名字叫做小明的,把年龄更改为16岁:
db.student.update({"name":"小明"},{$set:{"age":16}});
查找数学成绩是70,把年龄更改为33岁:
db.student.update({"score.shuxue":70},{$set:{"age":33}});
更改所有匹配项目:”
By default, the update() method updates a single document. To update multiple documents, use the multi option in the update() method.
db.student.update({"sex":"男"},{$set:{"age":33}},{multi: true});
完整替换,不出现$set关键字了:
db.student.update({"name":"小明"},{"name":"大明","age":16});
4 删除数据
默认情况下情况满足的都会删除
db.restaurants.remove( { "borough": "Manhattan" } )
By default, the remove() method removes all documents that match the remove condition. Use the justOne option to limit the remove operation to only one of the matching documents.
加上justOne: true表示只删除满足条件的第一个元素
db.restaurants.remove( { "borough": "Queens" }, { justOne: true } )
删除restaurants集合下的所有数据
db.restaurants.remove( {} )
5 Node.js操作MongoDB
首先:
Node.js安装MongoDB
npm install mongodb
API可以查看手册https://docs.mongodb.org/manual/
或者直接查看http://mongodb.github.io/node-mongodb-native/2.2/quick-start/quick-start/
案例1:
访问127.0.0.1/都会往数据库写入组对象
var express = require('express');var app = express();//在Node中引入mongodb模块var MongoClient = require('mongodb').MongoClient;//设置要链接的数据库URL,myproject为我们数据库的名字var url = 'mongodb://localhost:27017/myproject';//使用数据库连接服务app.get('/',function(req,res){ // 回调函数中,err为错误,db为数据库 MongoClient.connect(url, function(err, db) { //在数据库中简历集合'documents' var collection = db.collection('documents'); //向集合中插入一组文档 collection.insertMany([ {a : 1}, {a : 2}, {a : 3} ], function(err, result) { console.log("Inserted 3 documents into the collection"); }); //关闭数据库,正规的就是每一次操作都要打开和闭合数据库 db.close(); });})app.listen(3000);
结果:
04—案例01
案例2:
目录:
列出所有数据库中的数据
index.ejs:
<!doctype html><html lang="en"><head> <meta charset="UTF-8"> <title></title> <style type="text/css"> table,tr,td{ border:1px solid black; border-collapse: collapse; } tr:nth-child(2n){ background-color: pink; } </style></head><body> <h1>学生管理系统</h1> <a href="/add">添加学生</a> <table> <tr> <th>姓名</th> <th>年龄</th> <th>数学分数</th> <th>语文分数</th> </tr> <% for(var i = 0 ; i < result.length ; i++){%> <tr> <td><%= result[i].name %></td> <td><%= result[i].age %></td> <td><%= result[i].score.yuwen %></td> <td><%= result[i].score.shuxue %></td> </tr> <%}%> </table></body></html>
add.ejs:
<!doctype html><html lang="en"><head> <meta charset="UTF-8"> <title></title> <style type="text/css"> </style></head><body> <h1>学生管理系统</h1> <form action="/tijiao" method="get"> <p> 姓名: <input type="text" name="name"/> </p> <p> 年龄: <input type="text" name="age"/> </p> <p> 数学成绩: <input type="text" name="shuxuechengji"/> </p> <p> 语文成绩: <input type="text" name="yuwenchengji"/> </p> <p> <input type="submit"/> </p> </form></body></html>
Node.Js:
var express = require("express");var MongoClient = require('mongodb').MongoClient;var app = express();//设置模板引擎app.set("view engine","ejs");//数据库连接的地址,最后的斜杠后面表示数据库名字var shujukuURL = 'mongodb://localhost:27017/itcast';app.get("/",function(req,res){ //先连接数据库,对数据库的所有操作,都要写在他的回调函数里面。 MongoClient.connect(shujukuURL, function(err, db) { if(err){ res.write("数据库连接失败"); return; } //查询数据库,遍历所有数据到docs db.collection('teacher').find({}).toArray(function(err, docs){ if(err){ res.write("遍历错误"); return; } res.render("index",{ "result" : docs }); db.close(); }); });});app.get("/add",function(req,res){ res.render("add");});app.get("/tijiao",function(req,res){ //得到参数 var name = req.query.name; var age = req.query.age; var yuwenchengji = req.query.yuwenchengji; var shuxuechengji = req.query.shuxuechengji; MongoClient.connect(shujukuURL, function(err, db) { if(err){ console.log("数据库连接失败"); return; }//将学生的数据存到数据库中 db.collection("teacher").insertOne({ "name" : name, "age" : age, "score" : { "shuxue" : shuxuechengji, "yuwen" : yuwenchengji } },function(err,result){ if(err){ console.log("数据库写入失败"); return; } res.send("恭喜,数据已经成功插入"); //关闭数据库 db.close(); }); });});app.listen(3000);
结果:
第一次访问http://127.0.0.1:3000/:
添加学生http://127.0.0.1:3000/add,并且填写相关的信息:
这时我们查看数据库:
这时我们再一次查看http://127.0.0.1:3000/会发现:
04—案例02
6封装DAO
开发DAO:J2EE开发人员使用数据访问对象(DAO)设计模式把底层的数据访问逻辑和高层的商务逻辑分开.实现DAO模式能够更加专注于编写数据访问代码.
使用我们自己的DAO模块,来实现数据库插入。代码变得简单。
我们这里把常用的增删改查,都封装成为module。(将API进行了简单的封装)
目录结构:
db.js就是我们要封装的js:
(下面的查找中包含了分页和总数,可以在7中查看)
//这个模块里面封装了所有对数据库的常用操作var MongoClient = require('mongodb').MongoClient;var settings = require("../settings.js");//不管数据库什么操作,都是先连接数据库,所以我们可以把连接数据库//封装成为内部函数function _connectDB(callback) { var url = settings.dburl; //从settings文件中,都数据库地址 //连接数据库 MongoClient.connect(url, function (err, db) { if (err) { callback(err, null); return; } callback(err, db); });}//插入数据exports.insertOne = function (collectionName, json, callback) { _connectDB(function (err, db) { db.collection(collectionName).insertOne(json, function (err, result) { callback(err, result); db.close(); //关闭数据库 }) })};//查找数据,找到所有数据。args是个对象{"pageamount":10,"page":10}为第3个参数,为了防止有的时候//可能会不传args而导致的传入的参数只有3个,这时第3个参数不再是args而是callbackexports.find = function (collectionName, json, C, D) { if (arguments.length == 3) { //那么参数C就是callback,参数D没有传。 var callback = C; var skipnumber = 0; //数目限制 var limit = 0; } else if (arguments.length == 4) { var callback = D; var args = C; //应该省略的条数,从第0页开始 var skipnumber = args.pageamount * args.page || 0; //数目限制 var limit = args.pageamount || 0; //排序方式 var sort = args.sort || {}; } else { throw new Error("find函数的参数个数,必须是3个,或者4个。"); return; } //连接数据库,连接之后查找所有 _connectDB(function (err, db) { db.collection(collectionName).find(json).skip(skipnumber).limit(limit).sort(sort).toArray(function(err, docs){ if (err) { callback(err, null); db.close(); //关闭数据库 return; } callback(null, result); db.close(); //关闭数据库 }) });}//删除exports.deleteMany = function (collectionName, json, callback) { _connectDB(function (err, db) { //删除 db.collection(collectionName).deleteMany( json, function (err, results) { callback(err, results); db.close(); //关闭数据库 } ); });}//修改exports.updateMany = function (collectionName, json1, json2, callback) { _connectDB(function (err, db) { db.collection(collectionName).updateMany( json1, json2, function (err, results) { callback(err, results); db.close(); }); })}//获得数据的总数exports.getAllCount = function (collectionName,callback) { _connectDB(function (err, db) { db.collection(collectionName).count({}).then(function(count) { callback(count); db.close(); }); })}
Node.js:
var express = require("express");var app = express();var db = require("./model/db.js");//插入数据,使用我们自己封装db模块,就是DAO。app.get("/charu",function(req,res){ //三个参数,往哪个集合中增加,增加什么,增加之后做什么 db.insertOne("teacher",{"name":"小红"},function(err,result){ if(err){ console.log("插入失败"); return; } res.send("插入成功"); });});//查找app.get("/du",function(req,res){ //这个页面现在接受一个page参数。 var page = parseInt(req.query.page); //express中读取get参数很简单 //查找4个参数,在哪个集合查,查什么,分页设置,查完之后做什么 db.find("canguan",{},{"pageamount":6,"page":page},function(err,result){ if(err){ console.log(err); } res.send(result); console.log(result.length); });});//删除app.get("/shan",function(req,res){ var borough = req.query.borough; db.deleteMany("canguan",{"borough":borough},function(err,result){ if(err){ console.log(err); } res.send(result); });});//修改app.get("/xiugai",function(req,res){ db.updateMany( "canguan", //集合名字 { "borough":"Manhattan" //改什么 }, { $set: { borough: "北京" } //怎么改 }, function(err,result){ //改完之后做什么 if(err){ console.log(err); } res.send(result); } );});app.listen(3000);
05—案例02
更多的可以查看
05—案例03
7将查到的数据分页,数据总数
分页,想想我们的百度百家Ajax案例,当时调用了百度的JSON,有一个参数叫做page=3,生成的JSON不一样。
这个就是分页,就是我们想寻找所有的新闻,但是是位于第3页的新闻。那么有两种做法:
1) 错误的做法: 就是讲所有的result都读取到数组,然后进行数据操作,进行分页;
2) 正确的做法: 就是真的在数据库中,只读取这么多内容。
错误的,我们试图每次都读取全部数据,但是这样开销很大。
var a = []; db.find("student",{},function(err,result){ for(var i = 10 * page ; i < 10 * (page + 1) ; i++){ a.push(result[i]); } res.send(a); });
所以,mongodb提供了傻傻的两个函数。
limit() 表示找几条数据
skip() 表示基础条数,展示的是skip()基础上的limit()条
假如第一页是page=0。每页10条,所以当前页的查询语句:
db.student.find({}).limit(10).skip(page*10)
数据总数怎么得到?
shell中可以查看:
db.student.stats().count;
05—案例02
8索引index
数据库中,根据一个字段的值,来寻找一个文档,是很常见的操作。比如根据学号来找一个学生。
这个学号,是唯一的,只要有学号,就能唯一确认一个学生的文档。学号这个属性,就非常适合建立索引,这样一来,查找学生就变得简单了。
1.这个语句,能够查看检索的过程:
db.student.find({"name":"user888"});
2.学生的姓名是唯一的,为了快速的进行检索,所以就把name属性建立成为“索引”:
db.student.createIndex({"name":1});
这样,今后通过name寻找student文档的时候,速度非常快。因为能够快速的从索引表中,找到这个文档。
缺点就是插入每条数据的时候,时间变慢了,效率低了。但是换回来的就是寻找的速度快了。
3.索引这个属性对应的属性值,所有的文档都不能相同:
db.members.createIndex( { "user_id": 1 }, { unique: true } );
那么”user_id”不能相同
07—案例shuoshuo
githup地址:https://github.com/haochangdi123/cleanUP-Node.js
- Mongodb
- MongoDB
- mongodb
- mongodb
- mongodb
- MongoDB
- mongodb
- MongoDB
- MongoDb
- mongodb
- MongoDB
- mongodb
- mongodb
- MongoDB
- MongoDB
- mongoDB
- MongoDB
- MongoDB
- BZOJ4568: [Scoi2016]幸运数字【线性基】
- Linux 同步方法剖析
- 算法:扑克牌的顺子问题
- Understanding the JVM(七)HotSpot算法实现
- android studio quick documentation,fetching documentation
- MongoDB
- 第一篇
- java语言基础 问题(数据类型问题)
- 手机上小东西
- Python入门(4)
- WordPress4.8.1版本存在XSS跨站攻击漏洞
- iOS11以及iPhone X遇到的相关问题
- 第20/21天 正则表达式
- windows10 dlib19 andaconda python3.6