文档章节

node.js中基本于expresss、mongodb的CRUD

yanwawa
 yanwawa
发布于 2013/08/15 17:13
字数 2145
阅读 170
收藏 0

需求还是基于前面的演示程序,只不过,我们把mysql换成了mongodb,因此,我们把以前的orm2插件更换成mongoose插件。

首先得下载mongodb文件,并启动服务器,这个过程大家可以参考我前面的spring data操作mongodb的文章。

在node.js项目中,我们需要先定义对象结构,建议大家把系统所有的对象结构定义到一个文件中,如果系统过大,可考虑按功能模块定义到多个文件中,我把对象结构定义到一个文件中,models.js,代码如下:

/**
 * 定义所有的对象结构,并通过exports向外导出.
 * User: ljh
 * Date: 13-8-13
 * Time: 下午4:44
 */
var mongoose = require('mongoose');

//连接是如何管理的,是否在这连接,有待深入研究???
mongoose.connect('mongodb://localhost/mydb');

var Schema  = mongoose.Schema;
//定义对象结构
var userSchema = new Schema({
    loginCode:{type:String},
    userName:{type:String},
    password:{type:String},
    picPath:{type:String},
    birthDay:{type:Date}
});

//定义集合,其中myUser是数据集的名称
exports.User =  mongoose.model("myUser", userSchema);


系统中需要操作user的地方,都需要引入models.js文件,例如:

var models  =  require("../commons/models");
var User = models.User;


下面是userAction.js中的核心CRUD代码,相对于orm2的api函数,mongoose的函数设计更为简洁、强大。

//首页
exports.index = function(req, res){
    //无缓存,应尽量避免以这种方式发回文件
    res.sendfile("public\\login.html");
};

//添加用户
exports.addUser = function(req, res) {
    var picPath = req.body.pic;
    if (!picPath || picPath.trim()=="") {
        picPath = "upload/photo.jpg";
    }
    var user = new User({
        userName:req.body.name,
        loginCode:req.body.loginCode,
        birthDay:req.body.birthday,
        password:req.body.password,
        picPath:picPath
    });
    user.save(function(err, u) {
        if (err) {
            var result = {'code':0,'msg':'添加用户失败:' + err};
            res.json(result);
        }  else {
            var result = {'code':1,'msg':'添加用户成功!'};
            res.json(result);
        }
    });
}

//批量删除用户 (uids为id字串,用-拼接,比如:1-3-4-5 )
exports.deleteUsers = function(req, res) {
    User.remove({ _id: { $in: req.params.uids.split("-")}}, function (err) {
        if (err) {
            var result = {'code':0,'msg':'批量删除用户失败:' + err};
            res.json(result);
        }  else {
            var result = {'code':1,'msg':'批量删除用户成功!'};
            res.json(result);
        }
    });
}

//删除用户
exports.deleteUser = function(req, res) {
    User.remove({_id:req.params.uid}, function(err) {
        if (err) {
            var result = {'code':0,'msg':'删除用户失败:' + err};
            res.json(result);
        }  else {
            var result = {'code':1,'msg':'删除用户成功!'};
            res.json(result);
        }
    }) ;
}

//修改用户
exports.modifyUser = function(req, res) {
    console.log("uid:" + req.params.uid);
    User.findById(req.params.uid, function(err, user){
        if (err) {
            commonsFun.handleError(err,"修改用户时查询用户失败!", res);
            return;
        }

        if (user) {
            user.userName = req.body.userName;
            if (req.body.password  && req.body.password != "***" && req.body.password.trim() != "") {
                user.password = req.body.password;
            }
            user.birthDay =  req.body.birthday;
            user.picPath = req.body.pic;
            console.log(user);
            user.save(function(err){
              if (err) {
                  var result = {'code':0,'msg':'修改用户失败:' + err};
                  res.json(result);
              }  else {
                  var result = {'code':1,'msg':'修改用户成功!'};
                  res.json(result);
              }
            });
        } else {
            var result = {'code':0,'msg':'要修改的用户可能不存在!'};
            res.json(result);
        }
    });
}

//根据id查询用户
exports.getUserById = function(req, res) {
    var uid =  req.params.uid;
    var result = {'code':0,'msg':'查询用户失败!'};

    User.findById(uid, "_id loginCode userName picPath birthDay" ,function(err, user){
       if (err) {
           commonsFun.handleError(err,"查询用户失败!", res);
           return;
       }
        if (user) {
            var result = {'code':1,'data':user};
            res.json(result);
        } else {
            res.json(result);
        }
    })

}

//显示用户分页列表
exports.user_list = function(req, res){
    var pno =  req.params.pno;
    var queryName = req.query.q_name;
    var pageSize = 3;
    var queryParm = {};
    //进行多条件的拼装
    if (queryName && queryName.trim() != "") {
         //如果用户输入了姓名
        queryParm.userName = new RegExp(queryName);
    }
    User.find(queryParm).count(function(err, userCount){
         if (err) {
             commonsFun.handleError(err, '取用户分页数据失败!' , res);
             return;
         };
         if (userCount > 0 ) {
             //查到了数据
             User.find(queryParm)
                 .limit(pageSize)
                 .skip((pno - 1)*pageSize)
                 .select("_id loginCode userName picPath birthDay")
                 .sort("loginCode")
                 .exec(function(err, users) {
                     if (err) {
                         commonsFun.handleError(err, '取用户分页数据失败!' , res);
                         return;
                     };
                     var p = new Page(pno, pageSize, userCount, users);
                     var result = {'code':1,'page':p};
                     res.json(result);
                 });
         } else {
             //没有查到数据
             var p = new Page(pno, pageSize, 0, []);
             var result = {'code':1,'page':p};
             res.json(result);
         }
    });
};

//得到登录用户状态
exports.getState = function(req, res){
    var user = req.session.user_key;
    var  resultJson ;
    if (user) {
        resultJson = {code:1,name:user.userName};
    }  else {
        resultJson =  {code:0,msg:'对不起,您没有登录!'};
    }
    res.json(resultJson);
};

//退出系统(这个方法应该返回json,我这仅仅为演示,直接返回登录页面了)
exports.logout = function(req, res){
    req.session.user_key = null;
    res.redirect("/")
}

//登录系统
exports.login = function(req, res){
    //express中得到参数req.body.uname或req.query.uname,其中,req.body可支持post,delete,put等方式
    console.log("user login, name is:" + req.query.uname + ",pwd is:" + req.query.pwd);

    var loginUser;

    User.findOne({loginCode:req.query.uname},function(err, user) {
        if (err) {commonsFun.handleError(err)};
        if (user && user.password == req.query.pwd) {
            req.session.user_key = user;
            res.send(JSON.stringify({code:1,name:user.userName}));
            return ;
        }
        res.send(JSON.stringify({code:0,msg:'用户名或密码错误,请核对!'}));
    });
};


基本代码和之前的orm2中基本类似,前台的html及js代码,没有做改动,大家在使用mongoose时,应注意下面一些常用的操作:

1、建立表空间,其中myUser是表空间名称

var User =  mongoose.model("myUser", userSchema);


userSchema是对象结构,通过如下方式定义:

var userSchema = new Schema({

  userName:{type:String},

  birthDay:{type:Date}

});


但也可以这样定义:

var User = mongoose.model("myUser",{userName:{type:String},birthDay:{type:Date}});

建立大家采用单独定义的方式,以增强可维护性。


2、关于查询

A、查单对象

User.findOne({userName:'张三'})

   .exec(function(err, user){

....

或者根据id来查询:

User.findById("52089d9a10986c140b000001", "_id loginCode userName picPath birthDay" ,function(err, user){....

其中,第二个参数是需要的对象属性,这比起orm2来说,方便了许多。


你也可以对查询出来的对象直接操作,findByIdAndUpdate,findByIdAndRemove都可以做这样的操作。


B、条件查询

User.find({password:"123",userName:"张三"}).exec....

上面的代码,是按给出的条件查询数据。


当然,你也可以用另一种方式来实现,比如:

.where("userName").equals("张三2")


如果想使用模糊查询,或其它更复杂的条件查询,可以使用正则,示例代码如下:

User.find({userName:new RegExp("^" + reg_str)})

如果不需要条件拼接,可以简单写成如下:

User.find({userName:{ $regex: /张/ },picPath:{$regex:/18/} })

在正则中:/^表示以什么开头,$/表示以什么结尾

mongoose中提供的另一个正则方法,我没有测试出效果,知道的同学可以告诉我一声:

.regex({userName:{$regex: /^张.*/ }}),这可怎么也运行不出来数据呢?呵呵


C、排序、分页、统计

排序:
.sort({userName:"desc"}),可以添加多个字段,asc为升序。
分页:
.skip(100).limit(20),其中skip的下标从0开始。
统计总记录条数:
count(function(err, rowCounts){})

详细实现,请大家参考上面的用户分页实现代码。


D、只需要部分属性

如果只需要部分属性,返回给前端,我们可以使用的两种方式,第一种是根据前端需要的字段手工构造这样的对象,另一种是在查询的时候,指定所需要的字段。比如:.select("userName birthDay __v"),或都某些查询函数可以指定所需要的属性。



3、新增、修改、删除

新增:

var user = new User({
        userName:req.body.name
    });
user.save(function(err, u)


修改:

User.update({password:"123"},{password:"888"},{ multi: true },function(err, counts){
    if (!err) {
        console.log("modify success, rows:" + counts) ;
    }  else {
        console.log(err);
    }
});
请注意如果要进行批量操作,设置multi为ture,否则,只会对第一条数据进行操作。

查是,对一个对象实例进行update,mongoose会报错,_id don't allow modify,原因是什么我没有深入研究,如果遇到这样的错误,大家可直接用save保存即可,具体请参阅上面的修改用户代码。


删除按api操作即可,没有太多要讲的。


4、对象关系的保存

有两种设计方案:

A、将对象直接保存到聚合根对象中

B、采用类似于关于数据库中的外键方式保存

我更偏向于第二种方案,这样做似乎更有利于查询的构建,当然,如果子对象是一个值对象,就可以用第一种方案了。示例代码如下,客户一对多订单:

A方案是这样定义的:

var customerSchema = new Schema({
    name:String,
    gender:Boolean,
    orders:[{
        orderNo:String,
        price:Number,
        amount:Number,
        customer:{type:Schema.Types.ObjectId, ref:"customer"}
    }]
});
var Customer =  mongoose.model("customer",customerSchema);


B方案定义:

var customerSchema = new Schema({
    name:String,
    gender:Boolean,
    orders:[{type:Schema.Types.ObjectId, ref:"order"}]
});

var orderSchema = new Schema({
    orderNo:String,
    price:Number,
    amount:Number,
    customer:{type:Schema.Types.ObjectId, ref:"customer"}
});

var Customer =  mongoose.model("customer",customerSchema);
var Order =  mongoose.model("order",orderSchema);


然而,在B方案中,当对象关系发生变化后,需要我们手工去更改属性,并保存,这点比起java世界中的hibernate要逊色很多。

如果在查询时,把关联对象也实例化,要用到populate,比如:

Order.findOne({"customer":"5209e14f38b0a28003000001"})
    .populate("customer", "name gender").exec...


5、关于乐观锁

mongoose会自动为每一个对象生成__v字段,用来保存版本号,但实际操作时,并没有发现对版本号字段进行自动累加,知道的同学请告诉我,目前只有暂时用下面的办法去做:

关于version锁:
User.findById("52089d9a10986c140b000001",function(err, user){
    user.password = "222";
    user.increment();
    user.save(function(err){
        console.log("save ok!");
    });
    console.log(user);
});
注意红色那句代码,这而似乎只有手工去增加,但不知道后面在update的时候,是否会做为where条件加上去。


最全的api,大家请去http://mongoosejs.com/docs/api.html查看,好了,这一版本的demo先到些,下一版本,我将把前台的展示更换为angularjs。



© 著作权归作者所有

yanwawa
粉丝 3
博文 7
码字总数 8706
作品 0
成都
项目经理
私信 提问
node.js操作数据库之MongoDB+mongoose篇

前言 的出现,使得用前端语法(javascript)开发后台服务成为可能,越来越多的前端因此因此接触后端,甚至转向全栈发展。后端开发少不了数据库的操作。 是一个基于分布式文件存储的开源数据库系...

champyin
10/13
0
0
JS服务端系列-nodejs+express+ejs+mongodb的数据显示

1.我们下载好mongodb数据库,这个程序我放在nodejs的目录下了, 我的nodejs是安装在d: nodejs目录下,看图可以看到我的存放位置,这个随便放置 2.打开cmd窗口,转到mongodb的bin目录下, 执行...

透笔度
2015/08/05
739
0
使用express框架时,用MongoDB存放session时,出现错误,解决方法

使用express框架时,用MongoDB存放session时,出现错误如下: D:WorkSpacenodejsusernodemodulesconnect-mongolibconnect-mongo.js:153 throw new Error('Error connecting to database'); ......

maweitao
2014/04/11
100
0
利用node.js和mongodb为你的app写一个web服务

在当今这个协作和社交应用的世界里,其关键是要有一个能简单构建和易于部署的后台。许多组织机构都依赖于一个应用栈(Application Stack),其使用下面三项技术: 这个栈对于移动应用来说相当...

人生天地间
2014/04/28
714
0
Node.js进阶教程第六步:MongoDB-何韬-专题视频课程

Node.js进阶教程第六步:MongoDB—4067人已学习 课程介绍 本课程讲述了MongoDB的安装配置和使用,操作数据库,操作数据集,数据类型和嵌套关联,数据的增删查改,聚合,索引,存储过程,备份还原...

pkutao
2017/01/23
0
0

没有更多内容

加载失败,请刷新页面

加载更多

秒杀系统思路

业务分析 技术挑战 请求响应要快:无论成功失败,需要尽快返回给用户 架构设计   前端:静态化   站点层:限制请求数   服务层:乐观锁写缓存   数据库CAP:读写高可用,一致性,扩容...

雷开你的门
3分钟前
4
0
最全的教育行业大数据解决方案,个个针对痛点

大数据的悄然兴起也带动了教育行业的革新,移动教育、云课堂等的出现,使得教育行业再次成为了可以中长期保持高景气的行业。然而,初涉数据领域的教育行业同时也面临着相当大的难题,还需要更...

朕想上头条
7分钟前
3
0
预约模块设计分析

1.预约功能描述: 预约是小程序中常见的一种商品管理系统,商家可根据商品或服务的特性,灵活设置预约细节,为用户提供线上预约服务,如场地预约,商品预定等,实现高效经营。 预约场景: ...

鱼煎
11分钟前
3
0
阿里云日志服务构建网站实时分析大盘实战

场景分析 挖掘数据价值是当前企业级网站共同面临的问题。买买网是一个电商平台网站,每天拥有大量的用户访问和购买记录。为了引导用户直接消费,提升购买率和转化率,不同的用户类别需要推荐...

阿里云官方博客
12分钟前
2
0
TL665xF-EasyEVMTL665xF-EasyEVM开发板硬件处理器、NAND FLASH、RAM

广州创龙结合TI KeyStone系列多核架构TMS320C665x及Xilinx Artix-7系列FPGA设计的TL665xF-EasyEVM开发板是一款DSP+FPGA高速大数据采集处理平台,其底板采用沉金无铅工艺的6层板设计,适用于高...

Tronlong创龙
15分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部