MEAN Stack - MongoDB

2016-11-10  本文已影响0人  kevinscake

该文章为网络课 Introduction to MongoDB using the MEAN Stack学习笔记。

1. Mongoose

1.1 简介

是一个在node.js上使用的API。功能上作为一种ODM(Object Document Mapper),可以让程序猿以一种面向对象的方式进行数据的创建和存取,将对象转换为实际存储的BSON document则由mongoose来内部转换。

Mongoose

1.2 Mongoose的四种数据类型

一些socket对象,这些socket将mongoose连接到了mongoDB的某个database。

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() { 
  // we're connected!
});

连接上了db之后,所有代码在'open'事件的callback里面写。

一些对document所包含内容的规定,比如,包含的field,每个field的一些性质等等

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var blogSchema = new Schema({ 
  title: String, 
  author: String, 
  body: String, 
  comments: [{ body: String, date: Date }], 
  date: { type: Date, default: Date.now }, 
  hidden: Boolean, 
  meta: { votes: Number, favs: Number }});
  • 每一个key定义了一个对象的property,即对应了document中的一个property

可以把model看作是面向对象中的Class,它利用了schema进行定义,并且在之后用来构造document。

var Blog = mongoose.model('Blog', blogSchema, 'blogs');

此处定义了一个名为'Blog'并且利用了blogSchema的model, 它所对应数据库中的collection名字叫‘blogs’。注意,当第三个参数省略时,Mongoose automatically looks for the plural version of your model name.

var blog = new Blog({
    title: "kevin's blog"
    ...
});
Mongoose四种数据类型

2. Schema Design

2.1 Rule 1: Store What You Query For

MongoDB的改写和读取单个document的数据很快,但是它不支持join操作,因此,它不能够用一条语句来对不同document对象的数据进行query。因此,在设计schema之初,设计者最好能够以后要在一条query中取得的东西存在一个document之中,即"The way you store data should reflect how you use it in your application"

2.2 Rule 2: Least Cardinality

由于MongoDB的document中可以存array,因此看起来似乎解决了oneToMany的关系,但是,由于MongoDB中对单个文件的长度有限制,因此,这个性质不建议用当所要存储在array中的对象的数量没有上限时的应用。这时候应该将存储denormalize分散开来。

3. 更多

3.1 Index

将document中的某个field进行index来提升利用这个field查询数据时的效率。原理是:

当需要index的field是个array时,这时候叫做multi-key index

index有两种方式:

  1. 在filed定义的时候( field level)
  2. 在schema定义完之后(schema level), 组合索引(compound indexes)只能是这种定义方式。
var animalSchema = new Schema({ 
    name: String, 
    type: String, 
    tags: { type: [String], index: true } // field level
});

animalSchema.index({ name: 1, type: -1 }); // schema level
  • compund index: 先对name排序,在此基础上再对type排序
  • 1表示index order是ascending,-1表示descending

3.2. Virtuals

mongoose可以利用已经在schema中定义的属性(property)来定义一种虚拟属性(property)。之所以是虚拟的,是在于这种属性并不是真实存在document中的,即并不是真实存于数据库中的。这种做是为了方便能够对query结果的定制化

举个例子:
schema, model, document定义如下:

// define a schemavar 
personSchema = new Schema({ name: { first: String, last: String }});
// compile our modelvar 
Person = mongoose.model('Person', personSchema);
// create a documentvar 
bad = new Person({ name: { first: 'Walter', last: 'White' }});

假设我们需要得到文件bad的full name,一种做法是:

console.log(bad.name.first + ' ' + bad.name.last); // Walter White

利用virtuals,可以对schema定义一个virtual property getter

personSchema.virtual('name.full').get(function () { 
  return this.name.first + ' ' + this.name.last;
});

那么在query全名的时候,就可以很方便地直接用bad.name.full:

console.log('%s is insane', bad.name.full); // Walter White is insane

值得注意的是,如果因为某些需求,需要将document利用JSON.stringify()转成JSON string或者利用.toObject()转成一个plain Object时,default情况下并不能把virtual property转过来,如果想要将其保留过来的话,需要对schema做额外的设置:

schema.set('toObject', {virtuals: true});
schema.set('toJSON', {virtuals: true});

3.3 Custom Setter/Setter

Customer Setter

function toLower (v) {
  return v.toLowerCase();
}

var UserSchema = new Schema({
  email: { 
    type: String, 
    set: toLower //转小写setter
  } 
});

var User = mongoose.model('User', UserSchema);
var user = new User({email: 'AVENUE@Q.COM'});

console.log(user.email); // 'avenue@q.com'
// 此处只列出了schema定义的一部分
  ...
  price: {
    amount: { 
      type: Number,
      required: true,
      set: function(v) { //转USD setter
        this.internal.approximatePriceUSD =
          v / (fx()[this.price.currency] || 1);
        return v;
      }
    },
    // Only 3 supported currencies for now
    currency: {
      type: String,
      enum: ['USD', 'EUR', 'GBP'],
      required: true,
      set: function(v) { //转USD setter
        this.internal.approximatePriceUSD =
          this.price.amount / (fx()[v] || 1);
        return v;
      }
    }
  },
  ...

Customer Getter

当从mongoDB取出数据之后,需要做一些处理,使得document对象的value是处理后的值。

function obfuscate (cc) {
  return '****-****-****-' + cc.slice(cc.length-4, cc.length);
}

var AccountSchema = new Schema({
  creditCardNumber: {  
    type: String, 
    get: obfuscate // 模糊化getter
  }
});

var Account = mongoose.model('Account', AccountSchema);

Account.findById( someId, function (err, found) {
  console.log(found.creditCardNumber); // '****-****-****-1234'
});
上一篇 下一篇

猜你喜欢

热点阅读