zoukankan      html  css  js  c++  java
  • node连接--MongoDB

    简介:

    • 传统关系类型(ORM:Object-Relational Mapper),MongoDB(ODM:Object Document Mapper);
    • MongoDB是一个面向文档,schme无关(可以将任意类型的文档数据存储到集合中)的数据库;
    • MongoDB中可以将数据都看作文档,文档可以是任意深度的;
    • 当有数据存储后,这些文档会以十分接近JSON格式的形式存储;
    • 文档数据的数据类型可以是混合的,Node.js获取储存文档数据后,其类型和储存时候的类型是一样的;

    例子:

    • package.json:
      {
      	"name": "user-auth-example",
      	"version": "0.0.1",
      	"dependencies": {
      		"express": "2.5.8",
      		"mongodb": "1.3.19",
      		"jade": "0.20.3"
      	}
      }
    • 使用jade:  //缩进,默认两个空格 ; //注意tab和space不要混着用
      • views/layout.jade:
        doctype 5
        html
            head
                title MongoDB example
            body
                h1 My first MongoDB app
                hr
                block body
      • views/index.jade:
        extends layout
        block body
            if (authenticated)
                p Welcome back, #{me.email}
                a(href="/logout") Logout
            else
                p Welcome new visitor!
                ul
                    li: a(href="/login") Login
                    li: a(href="/signup") Signup
      • views/login.jade:
        extends layout
        block body
            form(action="/login", method="POST")
                fieldset
                    legend Log in
                    if (signupEmail)
                        #{signupEmail}
                        p Congratulations on signing up! Please login below
                    p
                        label Email
                        input(name="user[email]", type="text", value=signupEmail)
                    p
                        label Password
                        input(name="user[password]", type="password")
                    p
                        button submit
                    p
                        a(href="/") Go back
      • views/signup.jade:
        extends layout
        block body
            form(action="/signup", method="POST")
                fieldset
                    legend Sign up
                    p
                        label First
                        input(name="user[first]", type="text")
                    p
                        label Last
                        input(name="user[last]", type="text")
                    p
                        label Email
                        input(name="user[email]", type="text")
                    p
                        label Password
                        input(name="user[password]", type="password")
                    p
                        button Submit
                    p
                        a(href="/") Go back
    • server.js:
      var express = require('express');
      var mongodb = require('mongodb');
      var ObjectId = mongodb.ObjectID; 
      
      var app = express.createServer();
      
      
      
      //加入中间件
      app.use(express.bodyParser());
      app.use(express.cookieParser());
      app.use(express.session({secret: 'my secret'}));
      app.use(function(req, res, next) {                 //身份验证中间件
          if (req.session.loggedIn) {
              res.local('authenticated', true);   //express 的res.local   API
              app.users.findOne({"_id": ObjectId(req.session.loggedIn)}, function(err, doc) {
                  if (err) return next(err);
                  res.local('me', doc);
                  next()
              })
          } else {
              res.local('authenticated', false);
              next()
          }
      });
      
      
      
      
      app.set('view engine', 'jade');
      //express 3不需要这段代码
      app.set('view options', {layout: false});
      
      
      
      
      //创建mongodb.Server 初始化服务器
      var server = new mongodb.Server('127.0.0.1', 27017);
      
      //告诉驱动器连接数据库'my-website',不存在会创建
      new mongodb.Db('my-website', server, {w: 1}).open(function(err, client) {
          if (err) {
              throw err
          }
          console.log('33[96m + 33[39m connected to mongodb');
      
          //创建数据库操作集合的快捷方式
          app.users = new mongodb.Collection(client, 'users');
          // 不管索引是否存在,都可以调用这个命令来确保在查询前建立了索引
          client.ensureIndex('users', 'email', function(err) { 
              if (err) throw err
              client.ensureIndex('users', 'password', function() {
                  if (err) throw err
              });
              console.log('33[96m + 33[39m ensured indexes');
              app.listen(3000, function() {
                  console.log('33[96m + 33[39m app listening on *:3000');
              })
          })
      });
      
      
      
      
      app.get('/', function(req, res) {
          res.render('index')
      });
      app.get('/login', function(req, res) {
          if (req.session.loggedIn) {
              res.redirect('/');
          } else {
              res.render('login', {signupEmail: ''});
          }
      });
      app.get('/login/:signupEmail', function(req, res) {
          res.render('login', {signupEmail: req.params.signupEmail});
      });
      app.post('/login', function(req, res) {
          //文档查找
          app.users.findOne({email: req.body.user.email, password: req.body.user.password}, function(err, doc) {
              if (err) return next(err)
              if (!doc) return res.send('User not found. Go back and try again');
              req.session.loggedIn = doc._id.toString();
              res.redirect('/');
          })
      });
      app.get('/logout', function(req, res) {
          req.session.loggedIn = null
          res.redirect('/');
      });
      app.get('/signup', function(req, res) {
          res.render('signup');
      });
      app.post('/signup', function(req, res, next) {
          //创建文档
          app.users.insert(req.body.user, function(err, doc) {
              if (err) {
                  return next(err)
              }
              res.redirect('/login/' + doc[0].email);
          })
      });

    问题:

    • 校验://表单校验类型,大小等; mongoose通过在应用层定义scheme(模型)来解决;
    • 原子性://多个用户同时对同一文档进行了操作; mongoose通过检查要对文档做的修改,并只修改受影响的字段来解决;
    • 安全模式:在使用驱动时,对文档的操作中有一个可选参数: app.users.insert({},{<options>});其中safe选项对在对数据库进行修改时启动安全模式;默认情况下,在操作完成后,如果有错误发生,MongoDB不会及时通知;驱动器需要早操作后调用db.getLastError,来验证数据修改是否成功; mongoose默认会对所有操作启用安全模式;

    Mongoose://mongoose假定绝大部分应用程序都是用一个数据库;使用mongoose的时候无需关系连接是否建立,它会把数据库操作指令缓存起来,在连上数据库后发送出去;

    • 定义模型:类型包括Date,String,Number,Array,Object,ObjectId(MongiDB提供);例子:
      var Schema = mongoose.Schema;
      var ObjectId = Schema.ObjectId;
      
      
      //创建模型
      var PostSchema = new Schema({
           author : ObjectId,
           title: {type :  String, default: 'default' },  //选项格式
           body : String,
           date  : Date
      });
      
      //注册模型
      
      var Post = mongoose.model("BlogPost', PostSchema);
      
      
      //获取模型
      var Post = mongoose.modek('BlogPost');
      
      //操作模型:创建
      
      new Post({title: “My Title"}).save(function (err) {
         ....
      });  
    • 定义嵌套的键:
      var BlogPost = new Schema({
          title : String,
          meta  : {
              votes : Number,
              favs : Number
          }
      });
      //特定查找
      db.blogposts.find({'meta.votes':5});
    • 定义嵌套的文档:
      var Comments = new Schema({......});
      var BlogPost = new Schema({
        .....
        comments : [Comments],
        .....
      });
    • 构建索引:要对指定的键做索引,需要传递一个index选项,并将值设置为true;
      //设置title键做索引,并将uid键设置为唯一;
      
      var BlogPost = new Schema({
         author : ObjectId,
         title : {type: String, index : true},
         uid : {type : Number, unique : true}
      })
    • 中间件:有时候会在不同的地方以不同的方式对同样的数据进行修改,通过模型接口对这部分对数据库的交互集中避免代码重复;
      //定义一操作在特定动作前执行,如在删除博文时发送电子邮件给作者;
      Blogpost.prev('remove', function (next) {
          emailAuthor(this.email, 'Blog post removed!');
         next();
      });
    • 探测模型状态:根据要对当前模型做的不同更改进行不同操作
      Blogpost.prev('save', function(next) {
         if(this.isNew) {
         ....
         } else {
         .....
         }
      });
    • 查询:
      • find
      • findOne
      • findById //根据ObjectId
      • remove
      • update
      • count
    • 扩展查询:如果对某个查询不提供回调函数,那么直到调用run才会执行;
      Post.find({autor: '...'})
            .where('title','My title')
            .sort('content', -1)
            .limit(5)
            .run(function(err, post) {
             ...............  
            })
    • 排序:
      query.sort('key', 1);
      query.sort('some.key',-1);
    • 选择:若文档大,只想要指定部分;
      Post.find().select('field', 'field2');
    • 限制:现在查询结果的数量;
      query.limit(5);
    • 跳过:跳过指定数量的文档数据
      query.skip(10);
    • 自动产生键:
      //查询一个博文的时候,还获取对应的作者;为ObjectId类型提供一个href属性;
      var BlogPost = new Schema({
         author : {type : ObjectId, ref : 'Author'},
         title : String,
         body : String,
         meta : {
            votes : Number,
            favs : Number
         }
      })
      
      
      //对指定键调用populate就可自动生成;
      BlogPost.find({title : 'My title'})
            .populate('author')
            .run(function (err, doc) {
                console.log(doc.ahthor.email);
           });
    • 对上一个server.js使用mongoose之后:
      var express =  require('express');
      var mongoose = require('mongoose');
      
      
      //建立模型
      var Schema = mongoose.Schema;
      var User = mongoose.model('User', new Schema({
      	first: String,
      	last: String,
      	email: {type: String, unique: true},
      	password: {type: String, index: true}
      }));
      
      
      var app = express.createServer(
      	express.bodyParser(),express.cookieParser(),express.session({secret: 'my secret'})
      	);
      
      
      app.use(function(req, res, next) {
          if (req.session.loggedIn) {
              res.local('authenticated', true);
              User.findById(req.session.loggedIn, function(err, doc) {
                  if (err) return next(err);
                  res.local('me', doc);
                  next();
              });
          } else {
              res.local('authenticated', false);
              next();
          }
      });
      
      
      app.set('view engine', 'jade');
      app.set('view options', {layout: false});
      
      app.get('/', function(req, res) {
          res.render('index')
      });
      
      app.get('/login', function(req, res) {
          if (req.session.loggedIn) {
              res.redirect('/');
          } else {
              res.render('login', {signupEmail: ''});
          }
      });
      
      app.get('/login/:signupEmail', function(req, res) {
          res.render('login', {signupEmail: req.params.signupEmail});
      });
      
      app.post('/login', function(req, res) {
          //文档查找
          User.findOne({email: req.body.user.email, password: req.body.user.password}, function(err, doc) {
              if (err) return next(err)
              if (!doc) return res.send('User not found. Go back and try again');
              req.session.loggedIn = doc._id.toString();
              res.redirect('/');
          })
      });
      
      app.get('/logout', function(req, res) {
          req.session.loggedIn = null
          res.redirect('/')
      });
      
      app.get('/signup', function(req, res) {
          res.render('signup')
      });
      
      app.post('/signup', function(req, res, next) {
          var user = new User(req.body.user);
          user.save(function(err) {
          	if (err) return next(err);
          	res.redirect('/login/' + user.email);
          });
      });
      
      //连接数据库
      mongoose.connect('mongodb://127.0.0.1/my-website');
      app.listen(3000, function() {
      	console.log('33[96m + 33[39m app listening on *: 3000');
      });

     

  • 相关阅读:
    SpringMVC+Apache Shiro+JPA(hibernate)
    Win7系统上配置使用Intellij Idea 13的SVN插件
    标志一个方法为过时方法
    Java模板引擎 HTTL
    Spring security与shiro
    墨刀 手机app原型工具
    java远程调试(断点)程序/tomcat( eclipse远程调试Tomcat方法)
    结合MongoDB开发LBS应用
    基于LBS的地理位置附近的搜索以及由近及远的排序
    discuz 发布分类信息,能不能设置单版块去掉“发帖子”(默认点发帖后为自定义的默认分类信息模版)
  • 原文地址:https://www.cnblogs.com/jinkspeng/p/4126173.html
Copyright © 2011-2022 走看看