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

需求还是基于前面的演示程序,只不过,我们把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。



转载于:https://my.oschina.net/ljh2008/blog/152911

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值