一、概述

1. MongoDB提供了JavaScript环境下的BSON对象存储(一种JSON的二进制变种),用Node去读写数据非常高效

2. MongoDB把数据保存在内存里,很适合高并发写操作的情况,往MongoDB插入数据是非阻塞的,也很适合用来记录操作和远程数据

3. MongoDB支持在查询里嵌入JavaScript函数,还能进行MapReduce查询,读取数据的时候功能也很强大

4. 使用MongoDB的文档型存储,可以把子文档保存在母文档的内部,读取速度快

二、MongoDB原生驱动

1. 原生MongoDB驱动,提供了访问MongoDB的非阻塞方式

2. 原生MongoDB驱动的好处是,用户可以精确地控制MongoDB连接的操作

3. 安装

npm install mongodb

4. Node的MongoDB驱动支持的数据类型

Array,数据列表,scardsInHand: [9,4,3]
Boolean,真/假条件,hasBeenRead: false
Code,一段能在数据库中执行的JavaScript代码,new BSON.Code('function quotient(dividend,divisor){ return divisor == 0?0:divident/divisor; }');
Date,表示当前日期和时间,lastUpdated: new Date()
DBRef,数据库引用,MongoDB是非关系型数据库,所以它并不支持join操作,数据类型DBRef是客户端用来实现逻辑关系join的,bestFriendId:new BSON.DBRef('users',friendObjectId)
Integer,一个整数(非十进制)数,pageViews: 50 
Long,一个长整型值,starsInUniverse = new BSON.Long(10000000000000000000000000);
Hash,一个键值字典,userName: {'first': 'Sam', 'last': 'Smith'}
Null,一个空值,bestFriend: null
Object ID,MongoDB用来索引对象的12byte代码, 表示24位16进制字符串,myRecordId: new BSON.ObjectId()
String,一个JavaScript字符串,fullName: 'Sam Smith'

5. 连接到MongoDB并写入一条记录

const mongo = require('mongodb').MongoClient

const url = 'mongodb://localhost:27017'
const dbName = 'node-mongo-examples'

mongo.connect(url, {
    useNewUrlParser:true
}, (err, client)=>{
const db = client.db(dbName)
db.collection('users', (err, collection)=>{
    collection.insertOne({
        username: 'angus',
        firstname: 'angus',
    }, (err, docs)=>{
        console.log(docs.ops)
        client.close()
    })
})        
})

三、Mongoose

1. Node使用Mongoose库能够支持大量的Mongo操作,与原生的驱动相比,Mongoose是一个表达更加清楚的环境,让模型和架构更加直观

2. 安装Mongoose

npm install mongoose

3. 使用Mongoose

// 使用MongoDB的时候
// 不需要像关系数据库那样定义数据的结构
// 每当需求变更或者需要保存新的信息时
// 只要把包含新信息的记录保存进去
// 就能马上查询使用了

// Mongoose的作用在于
// 它使用了人可读的结构描述
// 提供了简洁的数据库交互接口

const mongoose = require('mongoose')
const Schema = mongoose.Schema
const ObjectId = Schema.Types.ObjectId

let maxConnectTimes = 0

// 定义schema

const AuthorSchema = new Schema({
    name: {
        first: String,
        last: String,
        full: String,
    },
    contact: {
        email: String,
        twitter: String,
        google: String,
    },
    photo: String
})

const CommentSchema = new Schema({
    commenter: String,
    body: String,
    posted: String,
})

const ArticleSchema = new Schema({
    author: {
        type: ObjectId,
        ref: 'AuthorSchema'
    },
    title: String,
    contents: String,
    published: Date,
    comments: [
        CommentSchema,
    ]
})

const Author = mongoose.model('Author', AuthorSchema)
const Article = mongoose.model('Article', ArticleSchema)

mongoose.connect('mongodb://127.0.0.1:27017/upandrunning', {
    useNewUrlParser: true
})
mongoose.connection.on('disconnect', ()=>{
    maxConnectTimes++;
    if(maxConnectTimes < 5){
        Mongoose.connect(db, { useNewUrlParser: true });
    }else{
        throw new Error("数据库挂了~");
    }
})
mongoose.connection.on('error', (err)=>{
    maxConnectTimes++;
    if(maxConnectTimes < 5){
        Mongoose.connect(db, { useNewUrlParser: true });
    }else{
        throw new Error("数据库连接出错了~");
    }
})
mongoose.connection.on('open', ()=>{
    console.log('MongoDB connected');
})

// 在数据库里保存了一条作者信息
new Author({
    name: {
        first: 'angus',
        last: 'charles',
        full: 'angus charles',
    },
    contact: {
        email: 'gsx0312@qq.com',
    } 
}).save((err)=>{
    if(err){
        console.log(err)
    }else{
        console.log('Author saved')
    }
    // 查询数据库把所有作者在屏幕上打印出来
    Author.find((err, doc)=>{
        console.log(doc)
        mongoose.disconnect()
    })
})

//  使用Mongoose的时候
//  不需要自己维护MongoDB的连接
//  所有的结构定义和查询都会被缓存起来
//  直到真的连接使用