MongoDB入門

數據庫服務器本質上是一個用於存儲數據的服務器;數據庫服務器中能夠放多個數據庫。javascript

1、3個概念

數據庫(database)html

數據庫是一個倉庫;能夠在倉庫中放多個集合。
複製代碼

集合(collection)java

集合相似於數據;在集合中能夠存放多個文檔。
複製代碼

文檔(document)mongodb

文檔是數據庫中的最小單位,咱們存儲操做的內容都是文檔。
複製代碼

3個概念的關係數據庫

在MongoDB中,數據庫和集合都不須要手動建立,當咱們建立文檔時,若是文檔所在的集合或者數據庫不存在會自動建立數據庫。json

2、數據庫操做(database)

啓動數據庫命令api

mongo
複製代碼

查詢全部數據庫數組

show dbs;
//or
show databases;
複製代碼

進入(建立)數據庫服務器

//進入(建立)my_test數據庫
use my_test;
複製代碼

若是my_test數據庫存在,則直接進入數據庫;mongoose

若是my_test不存在,則建立並進入數據庫。

3、集合操做(collection)

新建集合

//新建集合:number
db.createCollection('number')
複製代碼

查看集合List

show collections;
複製代碼

刪除集合

/** * @collectionName [集合名] */
db.collectionName.drop();
複製代碼

4、1.文檔操做——新增

友情提示:

文檔——增、刪、改、查的案例是基於以下的基礎上:

​ 新建一個數據庫todos,新建一個集合todo

增刪改查(CRUD)官網API地址

insertOne()

插入一條數據

/** * @todo [集合名] * @obj {Object} [要插入的數據] * * @TODO: * 只能插入一條 */
db.<collection>.insertOne(obj);
複製代碼

Example:

db.todo.insertOne({ name: 'a1', age: 10 })
//查詢todo集合中的全部文檔
db.todo.find();
//結果:{ "_id" : ObjectId("5cf64b69743e692169bbdbf7"), "name" : "a1", "age" : 10 }
複製代碼

insertMany()

插入多條數據

/** * @arr {Array|Object} [要插入的多條數據] */
db.<collection>.insertMany(arr)
複製代碼

Example:

db.todo.insertMany([ { name: 'a2', age: 11 }, { name: 'a3', age: 12 } ]);
db.todo.find();
/** 結果: { "_id" : ObjectId("5cf64e57743e692169bbdbfa"), "name" : "a1", "age" : 10 } { "_id" : ObjectId("5cf64e5e743e692169bbdbfb"), "name" : "a2", "age" : 11 } { "_id" : ObjectId("5cf64e5e743e692169bbdbfc"), "name" : "a3", "age" : 12 } */
複製代碼

insert()

插入多條or插入單條

/** * @data {Object|Array} [要插入的單條或者多條數據] * * @TODO: * * 即2個方法的合集 */
db.todo.insert(data);
複製代碼

Example: 同上面insertOne()insertMeny()的用法相同。

關於_id

當插入一個文檔沒有指定_id,則文檔會根據時間戳自動生成一個_id的值。

若是指定了_id,則使用_id做爲ID。

4、2.文檔操做——查詢

find()

返回全部符合條件的數據;

/** * @obj {Object} [須要篩選的條件] * @return {Array} [符合條件值的集合] */
db.todo.find(obj)
複製代碼

Example:

查詢name = a1的數據

db.todo.find({ name: 'a1' });
// { "_id" : ObjectId("5cf67ae40f133022c604d5b8"), "name" : "a1", "age" : 10 }
複製代碼

findOne()

返回符合條數據中的第一條數據;

Example:

/** * @obj {Object} [須要篩選的條件] * @return {Object} [符合條件的值] */
db.todo.find(obj)
複製代碼

count()

查詢符合條件的數據有多少條;

Example:

/** * @obj {Object} [須要篩選的條件] * @return {Number} [符合條件的值] */
db.todo.find(obj).count();
複製代碼

4、3.文檔操做——修改

update()

替換1個或者n個文檔的對象;

修改1個或者n個文檔的對象的值;

刪除1個或者n個文檔的對象的鍵;

/** * @filterObj {Any|Object} [篩選條件] * @newObj {Any} [新的值] * $set {Object} [修改對象的值] * $unset {Object} [刪除對象的鍵] * @config {Object} [配置項] * * multi {Boolean} [是否修改多個對象][default:false] * @TODO: * * 默認值修改篩選條件的第一個對象 */
db.<collection>.update(filterObj, newObj, config);
複製代碼

Example:

//將age=10的所有數據的name改成a14 
db.todo.update(
    {
        //篩選出age=10的數據
        age: 10
    }, 
    { 
        //將原數據中的name設置爲'a14'
    	$set: { 
        	name: 'a14'
        }
    }, 
    { 
        //修改多個數據
    	multi: true
    }  
)

//刪除掉 第一條name=a14的這條數據的name屬性
db.todo.update(
	{ 
    	name: 'a14'
    },
    {
        $unset: {
            name: 'a14'
        }
    }
)
複製代碼

$unset$set是MongoDB的文檔操做符;

更多的內容請查閱:MongoDB官網操做符

updateOne()

更新一條數據;

updateMany()

更新多條數據;

replaceOne()

替換第一條數據;

4、4.文檔操做——刪除

@TODO:

​ 在實際開發中,這個操做並不經常使用,由於實際上全部的刪除操做知識改變了數據的狀態,保證不會被輸出,可是實際上數據仍是存在於數據庫中。

remove()

刪除多個文檔或第一個;

deleteOne()

刪除第一個;

deleteMany()

刪除多個;

Example All Api

/** * 默認:刪除符合條件全部的文檔 @removeOne: true; 只刪除查詢條件的第一個 **/
db.<collection>.remove(query, removeOne);

//刪除多個
db.<collection>.deleteOne(query);

//刪除多個
db.<collection>.deleteMany(query);
複製代碼

4、5.文檔操做——練習題

  • 習題的知識點彙總:

比較操做符:

$gt:大於

$gte:大於等於

$lt:小於

$lte:小於等於

$eq:等於,必需要全等;

修改/新增/刪除操做符

$set:修改[value];新增{[key]: [value]}

unset: 刪除[key]

添加操做符

$push:向數組中添加一個值

$addToSet:向數組中添加一個值(被添加進來的值在這個數組中必須不存在)

方法

limit(n):取出n條數據;

skip(m):跳過第m條以前的數據,即從m+1條開始取。

Example

/** * [分頁] * @page {Number} [當前頁] * @page_size {Number} [每頁條數] * * @return {Object} * @data {Array} [符合條件的數據] * @total {Number} [總數量] */
function getDataList(page, page_size) {
    var skip = ( page - 1 ) + page_size;
    var data = db.<collection>.find({/*篩選條件*/});
    return {
        data: data.limit(page_size).skip(skip),
        total: data.count()
    };
}

複製代碼
  • 習題:

  • 答案:

//1
use my_test

//2
db.user.insert({ username: 'sunwukong' });

//3
db.user.find();

//4
db.user.insert({ username: 'zhubajie' });

//5
db.user.find();

//6
db.user.find().count();

//7
db.user.find({ username: 'sunwukong' })

//8
db.user.update(
    {
        username: 'sunwukong'
    },
    {
        $set: {
            address: 'huaguoshan'
        }
    },
    {
        //修改多個
        multi: true
    }
)

//9
db.user.update(
    {
        username: 'zhubajie'
    },
    {
        $set: {
            username: 'tangseng'
        }
    },
    {
        multi: true
    }
)

//10
db.user.update(
    {
        username: 'sunwukong',
    },
    {
        $unset: {
            // 這裏的值隨便填寫,主要是給:`$unset`添加一個鍵,準備刪除。
            address: 'delete'
        }
    },
    {
        multi: true
    }
)

//11
db.user.update(
    {
        username: 'sunwukong'
    },
    {
        $set: {
            hobby: {
                cities: ['beijing', 'shanghai', 'shenzhen'],
                movies: ['sanguo', 'hero']
            }
        }
    },
    {
        multi: true
    }
)

//12
db.user.update(
    {
        username: 'tangseng'
    },
    {
        $set: {
            hobby: {
                movies: ['A Chinese Odyssey', 'King of comedy']
            }
        }
    },
    {
        multi: true
    }
)

//13
db.user.find(
    {
        'hobby.movies': 'hero'
    }
)

//14
db.user.update(
    {
        username: 'tangseng'
    },
    {
        // 操做符:$push能夠向數組中添加數據
        // 操做符: $addToSet也能夠;區別是`$addToSet`對於重複數據不添加;$push則不會。
        $push: {
            'hobby.movies': 'Intersterllar'
        }
    }
)

//15
db.user.remove(
    {
        'hobby.cities': 'beijing'
    }
)

//16
db.user.drop();

//17.插入20,00條數據
var data = [];

for(var i = 1; i <= 1000*20; i++) {
        data.push( { num: i } )
}

db.numbers.insert(data) //建立numbers集合並插入2w條數據

//18.查詢num = 500的數據
numbers.find({ num: 500 })
//or
numbers.find({ num: { $eq: 500 } })
//區別:
// 前者會匹配數組中值爲500的數據;
// 後者只匹配num=500的數據;

//19.查詢num>5000的文檔
numbers.find({ num: { $gt: 5000 })

//20.查詢num>=19996的文檔
numbers.find({ num: { $gte: 19996 })

//21.查詢num<30的文檔
numbers.find({ num: { $lt: 30 })

//22.查詢 40 < num < 50 的文檔
numbers.find({ num: { $lt: 50, $gt: 40 } })

//23.查詢集合中前10條數據
numbers.find().limit(10)

//24.查詢集合中第11-20條數據
numbers.find().limit(10).skip(10)

//25.查詢第21-30條數據
numbers.find().limit(10).skip(20)

複製代碼

5、1.文檔間的關係

一對一(one to one)

一我的 對應 一個身份證號碼

db.human.insert({
    name: 'david',
    idcard: {
        idcard: 123465789102345678
    }
})
複製代碼

一對多(one to many)/ 多對一(many to one)

一個帳戶 對應 多個訂單

/** 用戶david有訂單 d一、d2,可使用d一、d2查詢到商品信息; 商品經過user_id能夠查詢到用戶; 一個訂單隻能對應一個用戶,一個用戶能夠擁有多個訂單。 */
db.users.insert({
    _id: 1,
    name: 'david',
    //訂單
    orders: ['d1', 'd2']
})

db.orders.insert([
    {
        user_id: 1,
        id: 'd1',
        name: '商品1'
    },
    {
        user_id: 1,
        id: 'd1',
        name: '商品1'
	}
])
複製代碼

多對多(many to many)

多個老師對應多個學生

/**

*/

db.teachers.insert([
    {
        tid: 't1',
        name: 't1',
        students: ['s1', 's2']
    },
    {
        tid: 't2',
        name: 't2',
        students: ['s1', 's2', 's3']
    },
    {
        tid: 't3',
        name: 't3',
        students: ['s1']
    }
])

db.students.insert([
    {
        sid: 's1',
        name: 's1
        students: ['t1', 't2']
    },
    {
        sid: 's2',
        name: 's2',
        students: ['t1', 't2', 't3']
    },
    {
        sid: 's3',
        name: 's3',
        students: ['t3']
    }
])
複製代碼

5、2.文檔間的關係——習題

知識點概括:

$or:或操做符,詳細用法見29題答案

$inc:自增操做符,詳細用法見33題答案

原始數據:

//dept.json
/* 1 */
{
    "_id" : ObjectId("5cf7c7c0ffd6ea864b5a22cc"),
    "deptno" : 10.0,
    "dname" : "財務部",
    "loc" : "北京"
}

/* 2 */
{
    "_id" : ObjectId("5cf7c7c0ffd6ea864b5a22cd"),
    "deptno" : 20.0,
    "dname" : "辦公室",
    "loc" : "上海"
}

/* 3 */
{
    "_id" : ObjectId("5cf7c7c0ffd6ea864b5a22ce"),
    "deptno" : 30.0,
    "dname" : "銷售部",
    "loc" : "廣州"
}

/* 4 */
{
    "_id" : ObjectId("5cf7c7c0ffd6ea864b5a22cf"),
    "deptno" : 40.0,
    "dname" : "運營部",
    "loc" : "深圳"
}

//emp.json
/* 1 */
{
    "_id" : ObjectId("5cf7ca79ffd6ea864b5a22d0"),
    "empno" : 7369.0,
    "ename" : "林沖",
    "job" : "職員",
    "mgr" : 7902.0,
    "hiredate" : ISODate("1980-12-16T16:00:00.000Z"),
    "sal" : 1200.0,
    "depno" : 20.0
}

/* 2 */
{
    "_id" : ObjectId("5cf7ca79ffd6ea864b5a22d1"),
    "empno" : 7499.0,
    "ename" : "孫二孃",
    "job" : "銷售",
    "mgr" : 7698.0,
    "hiredate" : ISODate("1981-02-19T16:00:00.000Z"),
    "sal" : 1600.0,
    "comm" : 300.0,
    "depno" : 30.0
}

/* 3 */
{
    "_id" : ObjectId("5cf7ca79ffd6ea864b5a22d2"),
    "empno" : 7521.0,
    "ename" : "扈三娘",
    "job" : "銷售",
    "mgr" : 7698.0,
    "hiredate" : ISODate("1981-02-19T16:00:00.000Z"),
    "sal" : 800.0,
    "comm" : 500.0,
    "depno" : 30.0
}

/* 4 */
{
    "_id" : ObjectId("5cf7ca79ffd6ea864b5a22d3"),
    "empno" : 7566.0,
    "ename" : "盧俊義",
    "job" : "經理",
    "mgr" : 7839.0,
    "hiredate" : ISODate("1981-02-19T16:00:00.000Z"),
    "sal" : 2975.0,
    "depno" : 20.0
}

/* 5 */
{
    "_id" : ObjectId("5cf7ca79ffd6ea864b5a22d4"),
    "empno" : 7654.0,
    "ename" : "潘金蓮",
    "job" : "銷售",
    "mgr" : 7839.0,
    "hiredate" : ISODate("1981-02-19T16:00:00.000Z"),
    "sal" : 2975.0,
    "depno" : 20.0
}

複製代碼

問題:

問題答案:

var emp = db.getCollection('emp')
var dept = db.getCollection('dept')

//33.爲全部工資低於1000的員工增長工資400元
emp.update({ sal: { $lte: 1000 } }, { $inc: { sal: 400 } })

//32.查詢全部mgr爲7698的全部員工
emp.find({ mgr: 7698 });

//31.查詢銷售部全部員工
var cwbId = dept.findOne({ dname: '銷售部' }).deptno
emp.find({depno: cwbId})

//30.查詢財務部的全部員工
var cwbId = dept.findOne({ dname: '財務部' }).deptno
emp.find({depno: cwbId})

//29.工資 >= 2500 或者 <= 1000
emp.find({ $or: [{sal: { $gte: 2500 }}, { sal: { $lte: 1000 } }] })

//28.工資1000-2000
emp.find({ sal: { $lte: 2000, $gte: 1000 } })

//27.工資<= 2000
emp.find({ sal: { $lte: 2000 } });
複製代碼

6、排序和投影

排序

sort()指定查詢文檔的篩選條件; sort()limit()skip()排序部分前後,由於總會先進行排序。

1:升序排列

-1:降序排列

默認:若是不指定sort(),則按照_id排序,而_id = 時間戳 + 機器碼組成,因此實際上默認是按照建立時間排序。

Example

//按照 工資 降序 排列
emp.find().sort({ sal: -1 })

//先按照 工資(sal) 升序;若是工資相同,再按照編號(empno) 降序排列
emp.find().sort({ sal: 1, empno: -1 })
複製代碼

映射

指定查詢時,須要返回的字段。

1:容許映射;

0:禁止映射;

//返回 工資(sal) >= 1250 的員工姓名
emp.find({ sal: { $gte: 1250 } }, { ename: 1 })
/*_id會自動加上 {"_id" : ObjectId("5cf7ca79ffd6ea864b5a22d1"),"ename" : "孫二孃"}, {"_id" : ObjectId("5cf7ca79ffd6ea864b5a22d2"),"ename" : "扈三娘"} {"_id" : ObjectId("5cf7ca79ffd6ea864b5a22d3"),"ename" : "盧俊義"} {"_id" : ObjectId("5cf7ca79ffd6ea864b5a22d4"),"ename" : "潘金蓮"} */

//若是想忽略_id,能夠嘗試:
emp.find({ sal: { $gte: 1250 } }, { ename: 1, _id: 0 })
複製代碼

7、1.操做MongoDB的庫——Mongoose

Mongoose是一個對象文檔模型(ODM)庫,他對Node原生的MongoDB模塊進行了進一步的優化封裝,並提供了更多的功能。

爲何要使用mongoose?

  • 能夠爲文檔建立一個模式結構(Schema|約束)
  • 能夠對模型中的對象/文檔進行驗證
  • 數據能夠經過類型轉換轉換爲對象模型
  • 可使用中間件來應用業務邏輯掛鉤
  • 比Node原生的MongoDB驅動更容易

7、2.mongoose——3個概念

Schema(模式對象)

Schema對象定義約束數據庫中的文檔結構

Model

Model對象做爲集合中的全部文檔的表示,至關於MongoDB數據庫中的集合collection

Document

Document表示集合中的具體文檔,至關於集合中的一個具體文檔。

建立順序:先有Schema約束Model,在用Model操做Document

7、3.Mongoose——第一個DEMO

鏈接數據庫,並插入第數據

const mongoose = require('mongoose');
var Schema = mongoose.Schema;

mongoose.connect(
  'mongodb://localhost:27017/mongoose_test', {useNewUrlParser: true}, function () {
  console.log('數據庫鏈接成功')
});

var stuSchema = new Schema({
  name: String,
  age: Number,
  gender: {
    type: String,
    default: 'woman'
  },
  address: String
})

var StuModel = mongoose.model('student', stuSchema)

StuModel.create({
  name: '孫悟空',
  age: 18,
  gender: 'man',
  address: '花果山'
}, function (err) {
  if(!err) {
    console.log('插入成功')
  }
})

StuModel.create({
  name: '白骨精',
  age: 18,
  address: '盤絲洞'
}, function (err) {
  if(!err) {
    console.log('插入成功')
  }
})
複製代碼

7、4.使用mongoose的Model進行增刪改查

Model的增/刪/改/查(CRUD)

.count(): 查詢數量

.create(): 新增

.find(): 查詢

.update(): 修改

.remove(): 刪除

const mongoose = require('mongoose');
const Schema = mongoose.Schema

let datas = [
  { name: '白骨精', age: 19, address: '盤絲洞'},
  { name: '孫悟空', age: 20, address: '花果山'},
  { name: '豬八戒', age: 21, address: '高老莊'},
  { name: '沙和尚', age: 22, address: '流沙河'}
]

const userSchema = new Schema({
  name: String,
  age: Number,
  sex: {
    type: String,
    default: 'man'
  },
  address: String
})

const userModel = mongoose.model('users', userSchema)

//查詢數量
userModel.count({}, function(err, count) {
  if(!err) {
    console.log(count)
  }
})

//寫入數據
userModel.create(datas, function(err) {
  if(!err) {
    console.log('寫入成功')
  }
})

/** * [查詢] * model.find(conditions, [projection], [options], [callback]) * @conditions {Object} [篩選條件] * @projection {Object|String} [投影] * * { name: 1, _id: 0 } * * 'name -_id' * @options {Object} [查詢選項:skip limit] * @callback {Function} [回調函數] * */
userModel.find({}, function (err, datas) {
  if(!err) {
    console.log( datas )
  }
})


/** * [修改] * model.update(conditions, docs, [options], [callback]) * @conditions {Object} [篩選條件] * @docs {Object|String} [修改的值] * @options {Object} [查詢選項:skip limit] * @callback {Function} [回調函數] * */
userModel.update({ name: '孫悟空' }, { $set: { age: 20 } }, function (err) {
  if(!err) {
    console.log( '修改爲功' )
  }
})

/** * [刪除] * model.remove(conditions, [callback]) * @conditions {Object} [篩選條件] * @callback {Function} [回調函數] * */
userModel.remove({  }, function (err) {
  if(!err) {
    console.log( '刪除成功' )
  }
})
複製代碼

7、5.使用mongoose的Document進行增刪改

Document是Model的一個實例,經過Model查詢到的結果都是Document

Document的增/刪/改(CUD)

const mongoose = require('mongoose');
const Schema = mongoose.Schema

mongoose.connect('mongodb://localhost:27017/mongoose_test', { useNewUrlParser: true }, function (err) {
  if(!err) {
    console.log('數據庫鏈接成功')
  } else {
    console.log('數據庫鏈接失敗' + err)
  }
})

const userSchema = new Schema({
  name: String,
  age: Number,
  sex: {
    type: String,
    default: 'man'
  },
  address: String
})

const userModel = mongoose.model('users', userSchema)

let datas = [
  { name: '白骨精', age: 19, address: '盤絲洞'},
  { name: '孫悟空', age: 20, address: '花果山'},
  { name: '豬八戒', age: 21, address: '高老莊'},
  { name: '沙和尚', age: 22, address: '流沙河'}
]

//插入一條數據
var user = new userModel({
  name: '玉帝',
  age: 10000,
  sex: 'woman',
  address: '天庭'
})
user.save(function (err, product) {
  if(!err) {
 console.log( '保存成功' )
}
})

// 修改數據1
userModel.findOne({}, function(err, doc) {
  if(!err) {
    doc.update({ $set: { sex: 'woman' } }, function (err) {
      if(!err) {
        console.log('修改爲功')
      }
    })
  }
})
// 修改數據2
userModel.findOne({}, function(err, doc) {
  console.log( doc.toJSON() )
  console.log( doc.toObject() )
  console.log( doc.toString() )
  if(!err) {
    doc.age = 80
    doc.save(function(err) {
      if(!err) {
        console.log('修改爲功')
      }
    })
  }
})

// 刪除數據
userModel.findOne({ name: '玉帝' }, function(err, doc) {
  if(!err) {
    doc.remove(function (err) {
      if(!err) {
        console.log('刪除成功')
      }
    })
  }
})
複製代碼

關於更多的mongooseapi請參閱 mongoose官網文檔

7、6.mongoose模塊化處理

爲何要模塊化?

在沒有模塊化以前,鏈接數據庫,建立SchameModel、數據CRUD都是在index.js文件中進行的,可是當一個應用有各類路由的時候,須要在各個頁面操縱各類Model,這樣在每一個頁面操縱Model的時候很是的困難,所以須要模塊化解決這個問題。

實施模塊化

未整理以前的目錄:

/index.js
複製代碼

模塊化以後的目錄:

/models
    /user.js
/schame
    User.js
index.js
mongoose_init.js
複製代碼

內容以下:

/schames/User.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema

const userSchema = new Schema({
  name: String,
  age: Number,
  sex: {
    type: String,
    default: 'man'
  },
  address: String
})

module.exports = userSchema
複製代碼

/models/user.js

const mongoose = require('mongoose');
const User = require('../schames/User')

const user = mongoose.model('users', User)

module.exports = user
複製代碼

mongoose_init.js

const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/mongoose_test', { useNewUrlParser: true }, function (err) {
  if(!err) {
    console.log('數據庫鏈接成功')
  } else {
    console.log('數據庫鏈接失敗' + err)
  }
})
複製代碼

index.js

require('./mongoose_init')
const user = require('./models/user')

user.find({}, function(err, data) {
  if(!err) {
    console.log(data) //查詢成功
  }
})
複製代碼
相關文章
相關標籤/搜索