nodejs操作mongodb数据库(mongoose)
来源:互联网 发布:星空倒影 知乎 编辑:程序博客网 时间:2024/04/29 05:10
准备
在上一篇的基础上,通过npm安装mongoose。
关于mongoose
Mongoose是MongoDB的一个对象模型工具,是基于node-mongodb-native开发的MongoDB nodejs驱动,可以在异步的环境下执行。同时它也是针对MongoDB操作的一个对象模型库,封装了MongoDB对文档的的一些增删改查等常用方法,让NodeJS操作Mongodb数据库变得更加灵活简单。
Schema : 一种以文件形式存储的数据库模型骨架,不具备数据库的操作能力
Model : 由Schema发布生成的模型,具有抽象属性和行为的数据库操作对
Entity : 由Model创建的实体,他的操作也会影响数据库
它们之间的关系是Schema生成Model,Model创造Entity,Model和Entity都可对数据库操作造成影响,但Model比Entity更具操作性。Model对应collection,Entity对应docment。
Mongoose API:http://mongoosejs.com/docs/api.html
CRUD操作
1.增加
如果是Entity,使用save方法,如果是Model,使用create方法
// mongoose 链接var mongoose = require('mongoose');var db = mongoose.connect('mongodb://127.0.0.1:27017/chm'); // 链接错误db.connection.on('error', function(error) { console.log(error);});db.connection.on("open", function () { console.log("——数据库连接成功!——"); });// Schema 结构var vipSchema = new mongoose.Schema({ name : {type : String, default : 'java'}, addr : {type : String}, addTime : {type : Date, default: Date.now}, age : {type : Number}});//中间件//save之前触发vipSchema.pre('save', function(next){ console.log("pre save"); next();});vipSchema.post('save', function (doc) { //doc是当前插入的文档 console.log(doc);});// modelvar vipModel = db.model('vip', vipSchema);// 增加记录 基于 entity 操作var doc = {name : 'java', age:20, addr:"shanghai"};var vipEntity= new vipModel(doc);vipEntity.save(function(error) { if(error) { console.log(error); } else { console.log('saved OK!'); } // 关闭数据库链接 db.disconnect();});//增加记录 基于model操作vipModel.create(doc, function(error){ if(error) { console.log(error); } else { console.log('save ok'); } // 关闭数据库链接 db.disconnect();});
这里有个问题,当执行完上面的代码后,到数据库中执行db.vip.find();命令你会发现查不到刚添加的那条数据,再执行show collections你会发现多了一个vips集合,数据在这个集合里面。这里Mongoose在模型名至数据库集合名的命名转换上做了文章,下面会介绍。
2.查找
var mongoose = require("mongoose");var db = mongoose.connect('mongodb://localhost:27017/chm'); db.connection.on("error", function (error) { console.log("数据库连接失败:" + error); }); db.connection.on("open", function () { console.log("——数据库连接成功!——"); });var Schema = mongoose.Schema;//模板var vipSchema = new Schema({ name:String, age:Number, addr:String, addTime:Date});// 添加 mongoose 实例方法vipSchema.methods.findByName = function(hello, callback) { return this.model('vips').find({name: hello}, callback);}// 添加 mongoose 静态方法,静态方法在Model层就能使用vipSchema.statics.findbyage = function(age, callback) { return this.model('vips').find({age: age}, callback);}//模型var vipModel = mongoose.model('vips', vipSchema);vipModel.find({name:"java"},function(error, result){ if(error) { console.log(error); } else { console.log(result); } //关闭数据库链接 db.disconnect(); });//基于实例方法的查询var entity = new vipModel({"name":"java"});entity.findByName("java",function(error, result){ if(error) { console.log(error); } else { console.log(result); } //关闭数据库链接 db.disconnect();});//基于静态方法的查询vipModel.findbyage(20, function(error, result){ if(error) { console.log(error); } else { console.log(result); } //关闭数据库链接 db.disconnect();;});
另一种查询:查询时不带回调
vipModel .find({ occupation: /host/ }) .where('name.last').equals('Ghost') .where('age').gt(17).lt(66) .where('likes').in(['vaporizing', 'talking']) .limit(10) .sort('-occupation') .select('name occupation') .exec(callback);
如果不带callback,则返回query,query没有执行的预编译查询语句,该query对象执行的方法都将返回自己,只有在执行exec方法时才执行查询,而且必须有回调。
3.修改
//省略上面相同代码......// 修改记录var conditions = {name : 'java'};var update = {$set : {age : 27}};var options = {upsert : true};vipModel.update(conditions, update, options, function(error){ if(error) { console.log(error); } else { console.log('update ok!'); } //关闭数据库链接 db.disconnect();});
4.删除
删除有2种方式,Entity和Model都使用remove方法
//省略上面相同代码......var conditions = {username: 'java'};vipModel.remove(conditions, function(error){ if(error) { console.log(error); } else { console.log('delete ok!'); } //关闭数据库链接 db.disconnect();});
Sub Docs
如同SQL数据库中2张表有主外关系,Mongoose将2个Document的嵌套叫做Sub-Docs(子文档)
简单的说就是一个Document嵌套另外一个Document或者Documents:
var ChildSchema1 = new Schema({name:String});var ChildSchema2 = new Schema({name:String});var ParentSchema = new Schema({ children1:ChildSchema1, //嵌套Document children2:[ChildSchema2] //嵌套Documents});
Sub-Docs享受和Documents一样的操作,但是Sub-Docs的操作都由父类去执行
var ParentModel = db.model('Parent',parentSchema); var parent = new ParentModel({ children2:[{name:'c1'},{name:'c2'}] }); parent.children2[0].name = 'd'; parent.save(callback);
parent在执行保存时,由于包含children2,他是一个数据库模型对象,因此会先保存chilren2[0]和chilren2[1]。
如果子文档在更新时出现错误,将直接报在父类文档中,可以这样处理:
ChildrenSchema.pre('save',function(next){ if('x' === this.name) return next(new Error('#err:not-x')); next(); }); var parent = new ParentModel({children1:{name:'not-x'}}); parent.save(function(err){ console.log(err.message); //#err:not-x });
4.1 查询子文档
如果children是parent的子文档,可以通过如下方法查询到children
var child = parent.children.id(id);
4.2 新增、删除、更新
子文档是父文档的一个属性,因此按照属性的操作即可,不同的是在新增父类的时候,子文档是会被先加入进去的。
如果ChildrenSchema是临时的一个子文档,不作为数据库映射集合,可以这样:
var ParentSchema = new Schema({ children:{ name:String }});//其实就是匿名混合模式
数据验证
数据的存储是需要验证的,不是什么数据都能往数据库里丢或者显示到客户端的,数据的验证需要记住以下规则:
- 验证始终定义在SchemaType中
- 验证是一个内部中间件
- 验证是在一个Document被保存时默认启用的,除非你关闭验证
- 验证是异步递归的,如果你的SubDoc验证失败,Document也将无法保存
- 验证并不关心错误类型,而通过ValidationError这个对象可以访问
7.1 验证器 - required 非空验证
- min/max 范围验证(边值验证)
- enum/match 枚举验证/匹配验证
- validate 自定义验证规则
以下是综合案例:
var PersonSchema = new Schema({ name:{ type:'String', required:true //姓名非空 }, age:{ type:'Nunmer', min:18, //年龄最小18 max:120 //年龄最大120 }, city:{ type:'String', enum:['北京','上海'] //只能是北京、上海人 }, other:{ type:'String', validate:[validator,err] //validator是一个验证函数,err是验证失败的错误信息 } });
7.2 验证失败
如果验证失败,则会返回err信息,err是一个对象该对象属性如下
err.errors //错误集合(对象)err.errors.color //错误属性(Schema的color属性)err.errors.color.message //错误属性信息err.errors.path //错误属性路径err.errors.type //错误类型err.name //错误名称err.message //错误消息
一旦验证失败,Model和Entity都将具有和err一样的errors属性。
Model至Collection的命名策略
mongoose/lib/util.js模块中如下代码片段是集合命名的根源。
function pluralize (str) { var rule, found; if (!~uncountables.indexOf(str.toLowerCase())){ found = rules.filter(function(rule){ return str.match(rule[0]); }); if (found[0]) return str.replace(found[0][0], found[0][1]); } return str;};
1.判断模型名是否是不可数的,如果是直接返回模型名;否则进行复数转化正则匹配;
2.返回复数转化正则匹配结果(一个复数转化正则匹配是一个数组,有两个对象,[0]正则表达式,[1]匹配后处理结果);
3.如果复数转化正则匹配结果不存在,直接返回模型名;否则取匹配结果第一个,对模型名进行处理。(需要说明的是,rules是按特殊到一般的顺序排列的)
部分内容来自:http://ourjs.com/detail/53ad24edb984bb4659000013
- nodejs操作mongodb数据库(mongoose)
- nodejs mongoose 操作mongodb 数据库封装
- Nodejs mongoose操作mongodb
- Mongoose – 让NodeJS更容易操作Mongodb数据库
- Mongoose - 让NodeJS更容易操作Mongodb数据库
- 利用mongoose操作mongodb数据库(一)
- mongoose 操作mongodb数据库的
- nodejs操作mongodb数据库(mongodb)
- nodejs操作mongodb数据库(mongodb)
- nodejs操作mongodb数据库(mongodb)
- nodejs和mongoose实现的对mongodb数据库进行的增删改查操作模板
- nodejs/express+mongodb/mongoose
- nodejs操作mongodb数据库
- nodejs操作mongodb数据库
- nodejs操作mongodb数据库
- 关于NodeJs为什么要用mongoose操作mongodb
- 关于NodeJs为什么要用mongoose操作mongodb
- nodejs操作mongodb数据库(转载)
- java之面向对象:继承extends、super、覆盖override的用法
- UML——用例图
- Geo server 发布shp格式地图
- WPF处理窗体的最小化事件及恢复正常窗体事件
- 用数学方法解约瑟夫环
- nodejs操作mongodb数据库(mongoose)
- ccpc 2016 合肥站 (5道题)
- Vue 固定头 固定列 点击表头可排序 表格组件
- 从1到n的n个整数中1出现的次数
- react-native 运行报Could not get BatchedBridge, make sure your bundle is packaged correctly 错误
- 关于ODBC和JDBC连接actian vortex数据库的bug报告
- Android中JNI开发的相关研究
- 浮点数转化为二进制整型
- JAVA从零单排-----继承、封装和多态详解