數據庫服務器本質上是一個用於存儲數據的服務器;數據庫服務器中能夠放多個數據庫。javascript
數據庫(database)html
數據庫是一個倉庫;能夠在倉庫中放多個集合。
複製代碼
集合(collection)java
集合相似於數據;在集合中能夠存放多個文檔。
複製代碼
文檔(document)mongodb
文檔是數據庫中的最小單位,咱們存儲操做的內容都是文檔。
複製代碼
3個概念的關係數據庫
在MongoDB中,數據庫和集合都不須要手動建立,當咱們建立文檔時,若是文檔所在的集合或者數據庫不存在會自動建立數據庫。json
啓動數據庫命令api
mongo
複製代碼
查詢全部數據庫數組
show dbs;
//or
show databases;
複製代碼
進入(建立)數據庫服務器
//進入(建立)my_test數據庫
use my_test;
複製代碼
若是my_test
數據庫存在,則直接進入
數據庫;mongoose
若是my_test
不存在,則建立並進入
數據庫。
新建集合
//新建集合:number
db.createCollection('number')
複製代碼
查看集合List
show collections;
複製代碼
刪除集合
/** * @collectionName [集合名] */
db.collectionName.drop();
複製代碼
友情提示:
文檔——增、刪、改、查的案例是基於以下的基礎上:
新建一個數據庫
todos
,新建一個集合todo
。
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。
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();
複製代碼
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()
替換第一條數據;
@TODO:
在實際開發中,這個操做並不經常使用,由於實際上全部的刪除操做知識改變了數據的狀態,保證不會被輸出,可是實際上數據仍是存在於數據庫中。
remove()
刪除多個文檔或第一個;
deleteOne()
刪除第一個;
deleteMany()
刪除多個;
Example All Api:
/** * 默認:刪除符合條件全部的文檔 @removeOne: true; 只刪除查詢條件的第一個 **/
db.<collection>.remove(query, removeOne);
//刪除多個
db.<collection>.deleteOne(query);
//刪除多個
db.<collection>.deleteMany(query);
複製代碼
比較操做符:
$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)
複製代碼
一對一(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']
}
])
複製代碼
知識點概括:
$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 } });
複製代碼
排序
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 })
複製代碼
Mongoose是一個對象文檔模型(ODM)庫,他對Node原生的MongoDB模塊進行了進一步的優化封裝,並提供了更多的功能。
爲何要使用mongoose?
Schema(模式對象)
Schema對象定義約束數據庫中的文檔結構
Model
Model對象做爲集合中的全部文檔的表示,至關於MongoDB數據庫中的集合collection
Document
Document表示集合中的具體文檔,至關於集合中的一個具體文檔。
建立順序:先有Schema約束Model,在用Model操做Document
鏈接數據庫,並插入第數據
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('插入成功')
}
})
複製代碼
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( '刪除成功' )
}
})
複製代碼
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('刪除成功')
}
})
}
})
複製代碼
關於更多的mongoose
api請參閱 mongoose官網文檔
爲何要模塊化?
在沒有模塊化以前,鏈接數據庫,建立Schame
、Model
、數據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) //查詢成功
}
})
複製代碼