第一種
安裝
在命令行中下載mongoose
npm install mongoose --save
引入mongoose并連接數(shù)據(jù)庫
// 引入第三方包mongoose
const mongoose = require('mongoose');
// 要管理員的賬號和密碼才能進(jìn)行數(shù)據(jù)庫操作
// mongoose.connect('mongodb://user:pass@localhost:port/database')
// user表示用戶名,pass表hi是密碼,port表示數(shù)據(jù)庫的端口mongodb的默認(rèn)端口27017,database表示數(shù)據(jù)庫的名字
// 連接數(shù)據(jù)庫
mongoose.connect('mongodb://127.0.0.1/blog', {
useUnifiedTopology: true,
useNewUrlParser: true
}).then(() => { //這里面的then()方法是如果成功輸出成功,如果失敗在catch()方法里面輸出失敗
console.log('數(shù)據(jù)庫成功');
}).catch(() => {
console.log('失敗');
});
配置Schema(通過require獲取)
就是
// 1.引入mongoose模塊
const mongoose = require('mongoose');
// 2.創(chuàng)建文章集合類型 定義一個Schema Schema里面的對象和數(shù)據(jù)庫表里面的字段需要一一對應(yīng)
const articleSchema = new mongoose.Schema({
title: {
type: String,
maxlength: 20, //最大長度
minlength: 4, //最小長度
required: [true, '請?zhí)顚懳恼聵?biāo)題'] //第一個參數(shù)是告訴這個是必填字段,第二個參數(shù)表示錯誤信息
},
author: {
type: mongoose.Schema.Types.ObjectId, //要將文章中的作者和用戶中的作者進(jìn)行關(guān)聯(lián)
ref: 'User', //這個屬性就是用來將文章集合和用戶集合進(jìn)行關(guān)聯(lián)’User‘就是集合的名字
required: [true, '請傳遞作者'],
},
publishDate: {
type: Date,
default: Date.now,
},
cover: {
type: Number,
default: 1 //表示默認(rèn)參數(shù),如果不寫,那么數(shù)據(jù)庫就會默認(rèn)為1
},
content: {
type: String
}
});
// 3.根據(jù)規(guī)則常見集合,定義數(shù)據(jù)庫模型 操作數(shù)據(jù)庫
// model 里面的第一個參數(shù)要注意首字母要大寫 2,要和數(shù)據(jù)庫表(集合名稱對應(yīng))
// 第二個參數(shù)要和Schema上面的一樣
const Article = mongoose.model('Article', articleSchema);
//Article會默認(rèn)和數(shù)據(jù)庫中的Articles進(jìn)行連接,我們也可以指定數(shù)據(jù)名詞,設(shè)置第三個參數(shù)就OK了
//這樣那么Article就和artes建立了連接
//const Article = mongoose.model('Article', articleSchema,'artes');
// 4.將集合規(guī)則作為模板成員進(jìn)行導(dǎo)出
module.exports = {
Article
}
模塊化配置
就是通過導(dǎo)入導(dǎo)出的方式來進(jìn)行模塊化
const mongoose = require('mongoose');
mongoose.connect('mongodb://127.0.0.1/blog', {
useUnifiedTopology: true,
useNewUrlParser: true
}).then(() => { //這里面的then()方法是如果成功輸出成功,如果失敗在catch()方法里面輸出失敗
console.log('數(shù)據(jù)庫成功');
}).catch(() => {
console.log('失敗');
});
// 導(dǎo)出數(shù)據(jù)
module.exports=mongoose;
引入數(shù)據(jù)庫
// 1.引入mongoose模塊
const mongoose = require('mongoose');
// 2.創(chuàng)建文章集合類型
const articleSchema = new mongoose.Schema({
title: {
type: String,
maxlength: 20, //最大長度
minlength: 4, //最小長度
required: [true, '請?zhí)顚懳恼聵?biāo)題'] //第一個參數(shù)是告訴這個是必填字段,第二個參數(shù)表示錯誤信息
},
author: {
type: mongoose.Schema.Types.ObjectId, //要將文章中的作者和用戶中的作者進(jìn)行關(guān)聯(lián)
ref: 'User', //這個屬性就是用來將文章集合和用戶集合進(jìn)行關(guān)聯(lián)’User‘就是集合的名字
required: [true, '請傳遞作者'],
},
publishDate: {
type: Date,
default: Date.now,
},
cover: {
type: String,
default: null
},
content: {
type: String
}
});
// 3.根據(jù)規(guī)則常見集合
const Article = mongoose.model('Article', articleSchema);
// 4.將集合規(guī)則作為模板成員進(jìn)行導(dǎo)出
module.exports = {
Article
}
操作那個數(shù)據(jù)庫引入就可以了
require('./')
操作添加,刪除,修改
預(yù)定義修飾符
lowercase、uppercase、trim
mongoose提供了預(yù)定義模式修飾符,可以對我們的數(shù)據(jù)進(jìn)行一些格式化
// 1.引入mongoose模塊
const mongoose = require('mongoose');
// 2.創(chuàng)建文章集合類型
const articleSchema = new mongoose.Schema({
title: {
type: String,
maxlength: 20, //最大長度
minlength: 4, //最小長度
required: [true, '請?zhí)顚懳恼聵?biāo)題'], //第一個參數(shù)是告訴這個是必填字段,第二個參數(shù)表示錯誤信息
trim:true //表示的是如果用戶輸入的數(shù)據(jù)兩邊有空格可以通過這個方法取消空格
}
});
自定義修飾符Getters與Setters
除了mongoose內(nèi)置的修飾符以外,我們還可以通過set(建議使用)修飾符在增加數(shù)據(jù)的時候?qū)?shù)據(jù)進(jìn)行格式化
也可以通過get(不建議使用)在實(shí)力獲取數(shù)據(jù)的時候?qū)?shù)據(jù)進(jìn)行格式化。
這是set方法
// 1.引入mongoose模塊
const mongoose = require('mongoose');
// 2.創(chuàng)建文章集合類型
const articleSchema = new mongoose.Schema({
title: {
type: String,
maxlength: 20, //最大長度
minlength: 4, //最小長度
required: [true, '請?zhí)顚懳恼聵?biāo)題'], //第一個參數(shù)是告訴這個是必填字段,第二個參數(shù)表示錯誤信息
trim:true //表示的是如果用戶輸入的數(shù)據(jù)兩邊有空格可以通過這個方法取消空格
pic:{
type:String,
set(parmas){ //增加數(shù)據(jù)的時候?qū)ic字段進(jìn)行處理
//parmas可以獲取pic的值、返回的數(shù)據(jù)就是pic在數(shù)據(jù)庫中實(shí)際保存的值
/**
*www.baidu.com http://www.baidu.com
*http://www.baidu.com http://www.baidu.com
*/
//如果用戶沒有傳入地址
if(!parmas){
return '';
}else{
if(parmas.indexOf('http://')!=0 $$ parmas.indexOf('http://')!=0){
return 'http://'+parmas;
}
return parmas;
}
}
} //表示自定義例如我們必須要http://www.baidu.com,但是有些用戶不輸入http://,所以需要進(jìn)行自定義設(shè)置
}
});
這是get方法可以去看一下,不好用
// 1.引入mongoose模塊
const mongoose = require('mongoose');
// 2.創(chuàng)建文章集合類型
const articleSchema = new mongoose.Schema({
title: {
type: String,
maxlength: 20, //最大長度
minlength: 4, //最小長度
required: [true, '請?zhí)顚懳恼聵?biāo)題'], //第一個參數(shù)是告訴這個是必填字段,第二個參數(shù)表示錯誤信息
trim:true //表示的是如果用戶輸入的數(shù)據(jù)兩邊有空格可以通過這個方法取消空格
name:{
type:String,
get(params){
return "a001"+params //表示的是在獲取數(shù)據(jù)的時候添加一個a001(只有同過什么.什么添加的時候)
}
}
}
});
Mongoose的索引
索引是對數(shù)據(jù)庫表中一列或多列的值進(jìn)行排序的一種結(jié)構(gòu),可以讓我們查詢數(shù)據(jù)庫變得更快,MONGODB的索引幾乎與傳統(tǒng)的關(guān)系型數(shù)據(jù)庫一模一樣,這其中也包括了一些基礎(chǔ)的查詢優(yōu)化技巧。
mongoose中除了以前創(chuàng)建索引的方式,我們也可以在定義Schema的時候指定創(chuàng)建索引。
// 2.創(chuàng)建文章集合類型 定義一個Schema Schema里面的對象和數(shù)據(jù)庫表里面的字段需要一一對應(yīng)
const articleSchema = new mongoose.Schema({
title: {
type: String,
// 唯一索引、
unique:true
},
cover: {
type: String,
/// 普通索引
index:true,
default: null
},
publishDate: {
type: Date,
default: Date.now,
},
content: {
type: String
}
});
mongoose內(nèi)置的CURD方法
[圖片上傳失敗...(image-4b0014-1601889185797)]
就是有的搜索時finByID我們也可以根據(jù)屬性來自定義一個
const articleSchema = new mongoose.Schema({
title: {
type: String,
maxlength: 20, //最大長度
minlength: 4, //最小長度
required: [true, '請?zhí)顚懳恼聵?biāo)題'] //第一個參數(shù)是告訴這個是必填字段,第二個參數(shù)表示錯誤信息
},
sn:{
},
content: {
type: String
}
});
//靜態(tài)方法(要加一個statics)
articleSchema.statics.findBySn=function(sn,cb){
this.find({"sn":sn},function(err,docs){
cd(err,docs);
})
}
//實(shí)例方法(基本沒用)
articleSchema.methods.print=function(sn,cb){
console.log(this)
}
// 然后存儲一個信息
var user=new articleSchema({
title:'2312',
sn:'123456',
content:'29'
});
user.save();
//靜態(tài)方法
// 通過Model.findBySn('123456',(){})來查詢數(shù)據(jù)
// 實(shí)例方法
//user.print();
數(shù)據(jù)校驗(yàn)
這是在Schema里面
required:表示這個數(shù)據(jù)必須傳入
max:用于Number類型數(shù)據(jù),最大值
min:用于Number類型數(shù)據(jù),最小值
enum:枚舉類型,要求數(shù)據(jù)必須滿足枚舉值 enum:['0','1','2']注意它使用在String類型中的
match:增加的數(shù)據(jù)必須符合match(正則)的規(guī)則 注意它使用在String類型中的
maxlenth:最大長度
minlength:最小長度
default:表示默認(rèn)值
自定義數(shù)據(jù)校驗(yàn)
const articleSchema = new mongoose.Schema({
title: {
type: String,
maxlength: 20, //最大長度
minlength: 4, //最小長度
required: [true, '請?zhí)顚懳恼聵?biāo)題'] //第一個參數(shù)是告訴這個是必填字段,第二個參數(shù)表示錯誤信息
},
content: {
type: String,
//自定義數(shù)據(jù)校驗(yàn) 任意的類型里面
validate:function(sn){
return sn.length>=10;
}
}
});
**mongoose中使用aggregate聚合管道(后期可以在看一下)
都可以寫多次
$project(篩選指定的列)
修改文檔結(jié)構(gòu),可以用來重命名,增加或刪除文檔中的字段。
要求查找order只返回文檔中的teade_no和all_price字段(order表示數(shù)據(jù)表)
order.aggregate([ //每一個管道是一個對象,對象里面實(shí)現(xiàn)具體的功能
{
$project:{teade_no:1,all_price1}
}
])
$match(過濾)
作用:用于過濾文檔,用法類似于find()方法中的參數(shù)。
order.aggregate([ //每一個管道是一個對象,對象里面實(shí)現(xiàn)具體的功能
{
$project:{teade_no:1,all_price1}
},
{
$match:{"all_price":{$gte:90}} //這個意思時查找總價格大于90的數(shù)據(jù)
}
])
$group???沒懂
將集合中的文檔進(jìn)行分組,可用于統(tǒng)計結(jié)果
統(tǒng)計每個訂單的訂單數(shù)量,按照訂單號分組
order.aggregate([ //每一個管道是一個對象,對象里面實(shí)現(xiàn)具體的功能
{
$group:{_id:"$order_id",total:{$sum:1}}
}
])
$sort(排序)
將集合文檔進(jìn)行排序
order.aggregate([ //每一個管道是一個對象,對象里面實(shí)現(xiàn)具體的功能
{
$project:{teade_no:1,all_price1}
},
{
$match:{"all_price":{$gte:90}} //這個意思時查找總價格大于90的數(shù)據(jù)
},
{
$sort:{"all_price":-1} //以 all_price進(jìn)行排序 -1降序 1升序
}
])
$limit(查幾條數(shù)據(jù))
order.aggregate([ //每一個管道是一個對象,對象里面實(shí)現(xiàn)具體的功能
{
$project:{teade_no:1,all_price1}
},
{
$match:{"all_price":{$gte:90}} //這個意思時查找總價格大于90的數(shù)據(jù)
},
{
$sort:{"all_price":-1} //以 all_price進(jìn)行排序 -1降序 1升序
},
{
$limit:1 //表示只返回一條數(shù)據(jù)
}
])
$skip (跳過幾條數(shù)據(jù))
order.aggregate([ //每一個管道是一個對象,對象里面實(shí)現(xiàn)具體的功能
{
$project:{teade_no:1,all_price1}
},
{
$match:{"all_price":{$gte:90}} //這個意思時查找總價格大于90的數(shù)據(jù)
},
{
$sort:{"all_price":-1} //以 all_price進(jìn)行排序 -1降序 1升序
},
{
$skip:1 //跳過幾條數(shù)據(jù)
}
])
$unwind
$unwind管道以document中的數(shù)組類型的字段進(jìn)行拆分,每條包含數(shù)組中的一個值。
比如拆分likes:10這條數(shù)據(jù),先來看看整體數(shù)據(jù)信息吧:
{
"_id" : ObjectId("5e86e2ad88e64443e448dfd2"),
"title" : "NoSQL Overview",
"description" : "No sql database is very fast",
"by_user" : "runoob.com",
"url" : "http://www.runoob.com",
"tags" : [
"mongodb",
"database",
"NoSQL"
],
"likes" : 10
}
router.get('/getInfo', async (req, res) => {
let data = await Content.aggregate([
{
$match: {
likes: 10
}
},
{
$unwind:'$tags'
},
{
$project: { _id: 1, by_user: 1, title: 1, title: 1, description: 1, url: 1, tags: 1, likes: 1 }
},
])
res.json({
data
})
})
$lookup(表關(guān)聯(lián)操作)
order.aggregate([ //每一個管道是一個對象,對象里面實(shí)現(xiàn)具體的功能
{
$lookup:{
from:"order_item", //就是你這個表要和那個表進(jìn)行關(guān)聯(lián)
localField:"order_id", //表示你order表關(guān)聯(lián)的字段
foreignField:"order_id", //表示你order_item表與order表關(guān)聯(lián)的id
as:"items" //as表示你要關(guān)聯(lián)的數(shù)據(jù)要放在哪里order的那個屬性里面
}
}
])
//想獲取的這樣的數(shù)據(jù)
[
{
Order_id:"",
Trade_no:"",
items:[
{
title:"鼠標(biāo)",
name:"名字"
},
{
title:"鍵盤",
name:"名字"
}
]
}
]
//要觀察誰關(guān)聯(lián)誰
db.order.insert([
{ order_id: "1", uid: 10, trade_no: "111", all_price: 100, all_num: 2 },
{ order_id: "2", uid: 7, trade_no: "222", all_price: 90, all_num: 2 },
{ order_id: "3", uid: 9, trade_no: "333", all_price: 20, all_num: 6 }
]);
//=================================
db.order_item.insert([
{ order_id: "1", title: "商品鼠標(biāo)1", price: 50, num: 1 },
{ order_id: "1", title: "商品鼠標(biāo)2", price: 50, num: 1 },
{ order_id: "1", title: "商品鼠標(biāo)3", price: 0, num: 1 },
{ order_id: "2", title: "牛奶", price: 50, num: 1 },
{ order_id: "2", title: "酸奶", price: 40, num: 1 },
{ order_id: "3", title: "礦泉水", price: 2, num: 5 },
{ order_id: "3", title: "毛巾", price: 10, num: 1 }
]);
//=================================
db.order.aggregate([
{
$project:{
order_id:1,
uid:1,
trade_no:1,
all_price:1,
all_num:1
}
},
{
$match:{
all_price:{
$gte:90
}
}
},
{
$sort:{
all_price:-1
}
},
{
$limit:2
},
{
$skip:1
},
{
$lookup:{
from:'order_item', // 要關(guān)聯(lián)的表
localField:'order_id', //order表中的order_id
foreignField:'order_id', // order_item表中的order_id
as:'items'
}
}
])
//=================================
db.order_item.aggregate([
{
$group:{
_id:'$order_id',total:{
$sum:'$num'
}
}
},
])
//=================================
db.order.aggregate([
{
$lookup:{
from:'order_item', // 要關(guān)聯(lián)的表
localField:'order_id', //order表中的order_id
foreignField:'order_id', // order_item表中的order_id
as:'items'
}
}
])
查詢一個表,找出商品名稱是酸奶的商品,酸奶這個商品對應(yīng)的訂單的訂單號以及訂單總價格。
//先查一個表,然后獲取出數(shù)據(jù),再通過獲取的數(shù)據(jù)查下一個表
OrderItemModel.find({"_ id":"5b743da92c327f8d1b360546"}, function(err,docs){
// console. log(docs);
var order_item=JSON. parse( JSON. stringify(docs));
var order_id=order_item[0].order_ id;
OrderModel. find({"order_ id":order_ id} ,function(err, order){
//
console. log(order);
order_ item[0] . order. info=order[0];
console. log(order_ item )
})
}
多個表的關(guān)聯(lián)存儲
這里就是通過輸入id來進(jìn)行關(guān)聯(lián)
[圖片上傳失敗...(image-b2baf1-1601889185798)]
//article.js文件
// 文章表,表結(jié)構(gòu)
var Schrma=mongoose.Schrma;
var ArticleSchema=new Schema({
title:{
type:String,
unique:true
},
cid:{
type:{
type:Schema.Types.ObjectId
},//分類ID
},
author_id:{
type:Schema.Types.ObjectId
},//用戶的id
author_name:{
type:String
},
descripton:String,
content:String
})
//文章分類
var ArticleSchema=new mongoose.Schema({
title:{
type:String,
unique:true
},
addtime:{
type:Date
},
descripton:String,
})
//用戶名
var ArticleSchema=new mongoose.Schema({
username:{
type:String,unique:true
},
password:String,
name:String,
age:Number,
sex:String,
tel:Number,
status:{
type:Number,
default:1
}
})
//分類增加
var cate=new 文章分類({
title:'國內(nèi)行文',
descripton:'國內(nèi)行文'
})
cate.save();
//增加用戶
var cate=new 用戶表({
username:'zhangfa ',
password:'nfusdhfk',
name:'sfsdaf',
age:20,
sex:'nan',
tel:20,
status:1
})
cate.save();
//文章表
var cate=new 文章表({
title:'習(xí)近平訪問',//國際新新聞
cid:'查找國際新聞的id與他關(guān)聯(lián)',
author_id:'獲取用戶的id與他關(guān)聯(lián)',//用戶的id
author_name:"獲取用戶的名與之關(guān)聯(lián)",
descripton:'我的描述’',
content:'這里面時內(nèi)容詳情'
})
cate.save();
mongoose實(shí)現(xiàn)多個表查詢Populate
mongoose使用關(guān)聯(lián)查詢的時候,你首先要知道主鍵與外鍵
要使用他之前要在Schema里面定義ref那個表的key有外鍵那個就是用ref
const articleSchema = new mongoose.Schema({
author: {
type: mongoose.Schema.Types.ObjectId, //要將文章中的作者和用戶中的作者進(jìn)行關(guān)聯(lián)
ref: 'User', //這個屬性就是用來將文章集合和用戶集合進(jìn)行關(guān)聯(lián)’User‘就是集合的名字
required: [true, '請傳遞作者'],
}
});
//查詢的方法
// 注意要是用populate需要引入用到的Moudel
//說建議用聚合管道查詢
let articles = await pagination(Article)//pagination分頁,
.find()//查詢
.page(page)//客戶端傳遞過來的頁碼
.size(2)//顯示幾個
.display(3)//最多
.populate("author") //populate('')這個方法里面存放的就是你要查詢的字段信息
.exec();
增加數(shù)據(jù)
//實(shí)例化Model 通過實(shí)例化User 的Molde創(chuàng)建添加數(shù)據(jù)
var admin = new User({
username: 'admin',
passworld: '123456',
email: 'admin@admin.com'
});
admin.save(function(err, ret) {//里面的兩個方法用來查看是否將數(shù)據(jù)存進(jìn)去
if (err) {
console.log('失敗');
} else {
console.log('成功');
console.log(ret);
}
})
一次性寫法:
new student(req.query).save(function(err, user) {
if (err) {
return next(err)
}
res.status(200).json({
err_code: 0,
message: 'OK',
user: user
})
})
查詢數(shù)據(jù)
? 查詢所有數(shù)據(jù):
// ***********************
// #region 查詢數(shù)據(jù)所有數(shù)據(jù)
// ***********************
User.find(function(err, ret) {
if (err) {
console.log('失敗');
} else {
console.log(ret);
}
})
按照條件查詢數(shù)據(jù)(查詢出來的是數(shù)組里面存放的是對象):
User.find({
username: '張三'
//年齡大于18去API查
}, function(err, ret) {
if (err) {
console.log('失敗');
} else {
console.log(ret);
}
})
按照條件查詢數(shù)據(jù)(查詢出來的是數(shù)據(jù)直接存放在對象中()):
User.findOne({ //如果第一個沒有參數(shù),那么查詢的就是第一個數(shù)據(jù)
username: '張三', //多個數(shù)據(jù)直接在后面跟就好了
passworld: '123456'
}, function(err, ret) {
if (err) {
console.log('失敗');
} else {
console.log(ret);
}
})
分析查詢
User.find(function(err, ret) {
if (err) {
console.log('失敗');
} else {
console.log(ret);
}
}).limit(1)//表示輸出第一行數(shù)據(jù)
user.getIndexes();
查詢方法
mongoose查詢使用最基礎(chǔ)的方法就是find、findOne方法,前者查詢所有滿足條件的值,后者取滿足條件的某一個值。
2、查詢條件
mongoose查詢條件其實(shí)就是在find方法的基礎(chǔ)上添加mongodb條件操作符,如Thing.find().gt('age', 21)就等同于Thing.find({age: {$gt: 21}}),mongodb條件操作符如下:
$or 或關(guān)系db.collection_name.find({$or: [{key1: value1}, {key2: value2}]})
$nor 或關(guān)系取反
$gt 大于
$gte 大于等于
$lt 小于
$lte 小于等于
$ne 不等于
$in 在多個值范圍內(nèi)
$nin 不在多個值范圍內(nèi)
$all 匹配數(shù)組中多個值
$regex 正則,用于模糊查詢
$size 匹配數(shù)組大小
$maxDistance 范圍查詢,距離(基于LBS)
$mod 取模運(yùn)算
$near 鄰域查詢,查詢附近的位置(基于LBS)
$exists 字段是否存在
$elemMatch 匹配內(nèi)數(shù)組內(nèi)的元素
$within 范圍查詢(基于LBS)
$box 范圍查詢,矩形范圍(基于LBS)
$center 范圍醒詢,圓形范圍(基于LBS)
$centerSphere 范圍查詢,球形范圍(基于LBS)
$slice 查詢字段集合中的元素(比如從第幾個之后,第N到第M個元素)
例如
tb_user.findOne({$or:[{user_name:req.body.user_name},{email:req.body.email}]},function(err,ret){
if(err){
console.log(err);
}else{
console.log(ret);
}
})
3、填充對象
查詢對象時,對象中存在其他對象的引用,查詢出來的引用對象默認(rèn)是顯示引用對象的id,如果需要引用對象的其他屬性就需要使用populate方法填充引用對象。
如果對以上知識點(diǎn)不太了解可以參考:
查詢實(shí)例
schema.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
name : { type: String, unique: true },
posts : [{ type: Schema.Types.ObjectId, ref: 'Post' }]
});
var User = mongoose.model('User', UserSchema);
var PostSchema = new Schema({
poster : { type: Schema.Types.ObjectId, ref: 'User' },
comments : [{ type: Schema.Types.ObjectId, ref: 'Comment' }],
title : String,
content : String
});
var Post = mongoose.model('Post', PostSchema);
var CommentSchema = new Schema({
post : { type: Schema.Types.ObjectId, ref: "Post" },
commenter : { type: Schema.Types.ObjectId, ref: 'User' },
content : {
main: String,
label: String
},
points: [
point: [{type: Schema.Types.ObjectId, ref: 'Point'}]
]
});
var Comment = mongoose.model('Comment', CommentSchema);
var PointSchema = new mongoose.Schema({
name: String,
parent: {type: Schema.Types.ObjectId, ref: 'point'},
children: [{type: Schema.Types.ObjectId, ref: 'point'}]
})
var Point = mongoose.model('Point', PointSchema);
1、深層屬性查詢
有些對象結(jié)構(gòu)比較復(fù)雜,屬性可能存在多層嵌套關(guān)系,有時需要通過對象屬性下屬的屬性查詢對象,如通過content的label的值查詢Comment
Comment.find({'content.label': value}, function (err, comment) {
console.log(comment)
})
2、二維數(shù)組查詢
如果二維數(shù)組結(jié)構(gòu)為[[]],這樣的數(shù)組是可以查詢,但是填充數(shù)組里對象時會有問題
Comment.find({'points': value}).populate('points').exec(function (err, comment) {
console.log(comment) // 無法填充points
})
所以需要填充二維數(shù)組里的對象時,不能使用這種結(jié)構(gòu),而應(yīng)該如schema.js中一樣,將里面的數(shù)組先作為對象保存
Comment.find({'points': value}).populate('points.point').exec(function (err, comment) {
console.log(comment) // 無法填充points
})
3、循環(huán)填充
結(jié)構(gòu)如Point,讀取point時,需要填充children,而childern的childern也需要填充,使用populate只能填充當(dāng)前的childern,在schema.js添加:
PointSchema.pre('find', function(next) {
this.populate('children')
next()
})
這樣每次查詢時,自動為point填充childern
4、多表聯(lián)合查詢
mongoose其實(shí)沒有多表聯(lián)合查詢的方法,不過我們可以通過多次查詢來實(shí)現(xiàn)。
通過user的name、post的content查詢post:
User.find({name: name}, function (err, users) {
Post.find({poster: {$in: users}, content: content}, function (err, posts) {
console.log(posts)
})
})
有時我們也需要對取出來的數(shù)據(jù)進(jìn)行再次過濾,而不是通過查詢語句查詢
通過user的name、post的content、comment的content.main查詢post:
User.find({name: name}, function (err, users) {
Post.find({poster: {$in: users}, content: content}).populate('commenter').exec(function (err, posts) {
posts.filter(function(post) {
return post.commenter.content.main === value
})
})
})
刪除數(shù)據(jù)
根據(jù)條件刪除所有
User.remove({
username: '張三'
}, function(err, ret) {
if (err) {
console.log('失敗');
}
console.log('成功');
console.log(ret);//所有的張三都刪除了
})
根據(jù)條件刪除一個
Model.findOneAndRemove(conditions,[options],[callback])
根據(jù)id刪除一個
Model.findByIdAndRemove(id,[options],[callback])
刪除的方法
Model.deleteOne(id,[options],[callback])
更新數(shù)據(jù)
根據(jù)條件更新所有:
//model就是數(shù)據(jù)表,你引入的表名
Model.update(conditions,doc,[options],[callback])
Model.updateOne(conditions,doc,[options],[callback])
根據(jù)指定條件更新一個:
Model.findOneAndUpdate([conditions],[update],[options],[callback])
根據(jù)id更新一個
// 第一個參數(shù)是他的MongoDB的id,第二個參數(shù)是你所想要修改的值,第三個是回調(diào)函數(shù)是否成功的
User.findByIdAndUpdate('5e0749619ca65b30b05a69ca', {
passworld: '123'
}, function(err, ret) {
if (err) {
console.log('失敗');
} else {
console.log('成功');
}
})
Mongodb 對內(nèi)嵌數(shù)組的增刪改查操作
先做一個初始化,設(shè)置一個User類,其初始數(shù)據(jù)如下:
{ arr: [ 1, 2 ],
_id: 5ac5ee12a79131259413c40f,
name: 'scy',
__v: 0 }
每次以初始數(shù)據(jù)為基,進(jìn)行操作。
1、向內(nèi)嵌數(shù)組添加數(shù)據(jù)
使用操作符 $push,向數(shù)組末尾添加數(shù)據(jù) ,可重復(fù)
//第一個參數(shù)是匹配條件 第二個參數(shù)是具體操作
User.update({name:"scy"},{$push:{"arr":3}});//向user里面的arr末尾追加元素3
結(jié)果如下:
{ arr: [ 1, 2, 3 ],
_id: 5ac5f0d3db343b1888a8969d, name: 'scy',__v: 0 }
一次添加多個數(shù)據(jù)
User.update({name:"scy"},{$push:{"arr":{$each:[2,3]}}});
router.get('/tijiao', function(req, res, next) {
student1.find(function(err, ret) {
if (err) {
console.log('失敗');
} else {
var now = new Date();
var nowStr = now.toLocaleString('chinese', { hour12: false });
req.query.data = nowStr;
req.query.changdu = ret.length + 1
new student1(req.query).save(function(err, ret) { //里面的兩個方法用來查看是否將數(shù)據(jù)存進(jìn)去
if (err) {
console.log('失敗');
} else {
console.log(req.query);
console.log(ret._id);
//注意就是這里將上一個''引號可以轉(zhuǎn)換
req.query.sid = ret._id + '';
student.update({ _id: req.query.id }, { $push: { 'shuzu': req.query } }, function(err, ret) {
if (err) {
console.log('失敗');
} else {
console.log('成功');
}
})
res.status(200).json({
err_code: 0,
message: 'OK',
ret: ret,
})
}
})
}
})
})
2、刪除內(nèi)嵌數(shù)組指定數(shù)據(jù)
注意添加的時候加一個''引號這樣可以將id轉(zhuǎn)為字符串
使用操作符 $pull
//刪除arr所有數(shù)據(jù)為2的元素
User.update({name:"scy"},{$pull:{"arr":2}});
執(zhí)行結(jié)果:
{ arr: [ 1 ], _id: 5ac5f39fdad94e23e8de9aee, name: 'scy', __v: 0 }
如果數(shù)組元素是對象,可以根據(jù)對象屬性操作:
{
name:"scy",
mArray:[{age:13,weight:50},{age:13,weight:30}]
}
User.update({name:"scy"},{$pull:{"mArray":{"weight":30}}});//刪除所有weight屬性值為30的對象
MongoDB,從數(shù)組中刪除對象
{
_id: 5150a1199fac0e6910000002,
name: 'some name,
items: [{
id: 23,
name: 'item name 23'
},{
id: 24,
name: 'item name 24'
}]
}
刪除代碼
User.update(
{'_id': ObjectId("5150a1199fac0e6910000002")},
{ $pull: { "items" : { id: 23 } } }
);
3、修改內(nèi)嵌數(shù)組指定數(shù)據(jù)
-
數(shù)據(jù)截圖:
[圖片上傳失敗...(image-e19f7e-1601889185798)]
-
我想更新arr_1數(shù)組中,a = 1 的對象,更新為 {a:11,b:12} 運(yùn)行更新代碼,如下:
[復(fù)制代碼](javascript:void(0);)
[db.nestedUpdate.updateMany({ 'arr_1.a': 1 }, { $set: { 'arr_1.$.a': 11, 'arr_1.$.b': 12, } }) 也可以:繼續(xù)存 $set: { "shuzu.$.sun8": [{ sun9: req.query.xuehao, sun10: req.query.xuehao, sun11: req.query.xuehao, }, { sun9: req.query.xuehao, sun10: req.query.xuehao, sun11: req.query.xuehao, sun12: '7', }] }復(fù)制代碼](javascript:void(0);)
我暫時還沒找到能批量修改數(shù)組元素的方法
1
3、修改內(nèi)嵌數(shù)組指定數(shù)據(jù)
我暫時還沒找到能批量修改數(shù)組元素的方法
//將數(shù)組里面的第一個元素1修改為3
User.update({"arr":{$all:[1]}},{$set:{"arr.$":2}});
//也可以根據(jù)下標(biāo)
User.update({$set:{"arr.1":22}});//將arr下標(biāo)為1的元素修改為22
如果數(shù)組的元素是對象,如下:
1
2
如果數(shù)組的元素是對象,如下:
{
name:"scy",
mArray:[{age:13,weight:50},{age:13,weight:30}]
}
修改操作如下:
User.update({"mArray.age":13},{$set:{"mArray.$.age":22}});//將第一個age為13的值修改為22
//還可以這樣 mArray.1.age 其中1是下標(biāo)
User.update({$set:{"mArray.1.age":22}});//將arr第二個元素對象的age改為22
批量修改內(nèi)嵌數(shù)組對象
//computer1數(shù)據(jù)表
//data.$[].network數(shù)組下面的數(shù)據(jù)
computer1.update({'roomNumber': req.query.w}, {$set: {'data.$[].network': 10}}, {multi: true},function(a,s){
console.log(a);
console.log(s);
})
4、查詢內(nèi)嵌數(shù)組并返回指定的數(shù)據(jù)
使用$size 返回指定數(shù)組長度的數(shù)據(jù)
//$size限制比較大 下面表示查詢數(shù)組長度為2的數(shù)據(jù)
User.find({arr:{$size:2}})
$slice,這個操作符還是比較強(qiáng)大的適合查詢數(shù)組中的數(shù)據(jù)
//匹配到的user 將其數(shù)組截取第一個返回 如[1,1,2]返回[1]
User.findOne({name:"scy"},{arr:{$slice:1}});
//將匹配到的user的數(shù)組 截取返回后面兩個元素 如[1,1,2]返回[1,2]
User.findOne({name:"scy"},{arr:{$slice:-2}});
//從數(shù)組的下表為1的元素開始 返回兩個 如[1,3,2]返回[3,2]
User.findOne({name:"scy"},{arr:{$slice:[1,2]}});
$elemMatch查詢的是某一個數(shù)據(jù)
用法如下:
User.findOne({name:"scy"},{arr:{$elemMatch:{key:val}});
總的代碼案例如下:
在當(dāng)前的目錄下的demo.js文件下
導(dǎo)出導(dǎo)入數(shù)據(jù)庫
首先要開啟數(shù)據(jù)庫連接通過mongod --dbpath 數(shù)據(jù)存儲目錄路徑 我的數(shù)據(jù)庫目錄地址好像在D:\mongoDB\two
然后在命令行中輸入
導(dǎo)出:
//-h表示主機(jī) -d表示要導(dǎo)出的數(shù)據(jù)庫 -o輸出的目錄
mongodump -h (主機(jī)127.0.0.1) -d (到處的數(shù)據(jù)庫) -o (地址)
//例如
mongodump -h 127.0.0.1 -d user -o C:\data
導(dǎo)入:
mongorestore -h (主機(jī)地址) -d (導(dǎo)入數(shù)據(jù)庫名) 導(dǎo)入的地址
第二種
8.MongoDB數(shù)據(jù)庫
8.1 關(guān)系型數(shù)據(jù)庫的非關(guān)系型數(shù)據(jù)庫
表就是關(guān)系
或者說表于表之間存在關(guān)系。
- 所有的關(guān)系型數(shù)據(jù)庫都需要通過
sql語言來操作 - 所有的關(guān)系型數(shù)據(jù)庫都需要設(shè)計表結(jié)構(gòu)
- 而且數(shù)據(jù)表還支持約束
- 唯一的
- 主鍵
- 默認(rèn)值
- 非空
- 非關(guān)系型數(shù)據(jù)庫可以說非常的靈活
- 有的非關(guān)系型數(shù)據(jù)庫就是key-value隊
- 在mingoDB是長得最像關(guān)系型數(shù)據(jù)庫的非關(guān)系型數(shù)據(jù)庫
- 數(shù)據(jù)庫-》數(shù)據(jù)庫
- 數(shù)據(jù)表-》集合(數(shù)組)
- 表記錄-》(文檔對象)
- MongoDB不需要設(shè)計表結(jié)構(gòu)
- 也就是說你可以任意的往里面存數(shù)據(jù),沒有結(jié)構(gòu)性這么一說
8.2安裝
- 64位下載地址:https://www.mongodb.com/what-is-mongodb
- 32位下載地址:https://www.mongodb.org/dl/win32/i386
- 配置環(huán)境變量
8.3啟動和關(guān)閉數(shù)據(jù)庫
啟動:
# mongodb 默認(rèn)使用執(zhí)行 mongdb 命令所處盤符根目錄下的/data/db 作為自己的數(shù)據(jù)存儲目錄
# 啟動的時候出現(xiàn)問題下面這張圖的問題
#需要在第一次執(zhí)行該命令之前先手動見一個 [c,d,盤]/data/db
在cmd中輸入mongodb
[圖片上傳失敗...(image-421fc9-1601889185798)]
如果想要修改默認(rèn)數(shù)據(jù)存儲目錄,可以:
mongod --dbpath=數(shù)據(jù)存儲目錄路徑
停止:
在開啟服務(wù)的控制臺,直接Ctrl+c即可停止
或者直接關(guān)閉開啟服務(wù)的控制臺也可以。
8.4連接數(shù)據(jù)庫
#該命令默認(rèn)連接本機(jī)的MongoDB服務(wù)
mongo
退出連接:
#在連接狀態(tài)輸入exit退出連接
exit
8.5基本命令
-
show dbs(查看顯示所有的數(shù)據(jù)庫) - db (查看當(dāng)前操作的數(shù)據(jù)庫)
-
use 數(shù)據(jù)庫名稱(切換到指定數(shù)據(jù)【如果沒有會新建】) - 插入數(shù)據(jù)
8.6在Node中如何操作MongoDB數(shù)據(jù)
8.6.1使用官方的mongodb包來操作
https://github.com/mongodb/node-mongodb-native#installation
8.6.2使用第三方的mongodb來操作Mongodb數(shù)據(jù)庫
第三方包:Mongodb基于Mongodb官方的mongodb包再一次做了封裝
第三方包連接數(shù)據(jù)庫
安裝:
npm i mongoose
#注意先下載npm i -y (如果有就不需要下載了)然后下載mongoose第三方的包
const mongoose = require('mongoose'); //引入mongoose包
//連接MongoDB數(shù)據(jù)庫
mongoose.connect('mongodb://localhost:27017/test', { useNewUrlParser: true });
// 這句先不了解
mongoose.Promise = global.Promise;
//創(chuàng)建一個模型
// 就是在設(shè)計數(shù)據(jù)庫
// MongoDB是動態(tài)的,非常靈活,只需要在代碼中設(shè)計你的數(shù)據(jù)庫就可以了
// mongodb這個包就可以讓你的設(shè)計編寫過程變的非常簡單
const Cat = mongoose.model('Cat', { name: String });
// 實(shí)例化一個Kitty
const kitty = new Cat({ name: 'Zildjian' });
// 持久化保存kitty實(shí)例
kitty.save().then(() => console.log('meow'));
持久化存儲for:
const mongoose = require('mongoose'); //引入mongoose包
// //連接MongoDB數(shù)據(jù)庫
mongoose.connect('mongodb://localhost:27017/test', { useNewUrlParser: true });
// // 這句先不了解
mongoose.Promise = global.Promise;
var Cat = mongoose.model('Cat', { name: String });
for (var i = 0; i < 50; i++) {
var kitty = new Cat({ name: '喵喵' + i });
kitty.save(function(err) {
if (err) {
console.log(err);
}
console.log('meow');
})
}
1.MongoDB數(shù)據(jù)庫的基本概念
- 數(shù)據(jù)庫
- 一個數(shù)據(jù)庫中有多個集合(表)
- 一個集合中可以有多個文檔(表記錄)
- 文檔結(jié)構(gòu)靈活,沒有任何限制
- MongoDB非常靈活,不像MySQL一樣要先創(chuàng)建數(shù)據(jù)庫,表,設(shè)計表結(jié)構(gòu)
- 在這里:當(dāng)你需要插入數(shù)據(jù)的時候,只需要指定往那個數(shù)據(jù)庫那個集合操作就可以
- 一切都由MongoDB來幫你自動完成建庫建表這件事
{
qq:{
//users:[{'這里存的是每一條記錄'對象}],//一個對象教文檔,要有一些約定,要不然亂
users:[
{},
{}
]
products:[
{name:'張三',age:15},
{name:'李四',age:16},
{name:'王五',age:17},
{name:'張三123',age:18},
...
]
},
taobao:{
},
baidu:{
}
}
mongoDB的案例構(gòu)建(案例案例)
設(shè)計Scheme發(fā)布Model
這些增刪改查的方法都是根據(jù)引入的包是var mongoose = require('mongoose');方法進(jìn)行的
與菜鳥聯(lián)盟的方法不同的原因是引入的包不同
var mongoose = require('mongoose');
// 獲取他的結(jié)構(gòu)
var Schema = mongoose.Schema;
// 指定連接的數(shù)據(jù)庫不需要存在,當(dāng)你插入第一條數(shù)據(jù)之后就會自動被創(chuàng)建出來
// 1.連接數(shù)據(jù)庫
mongoose.connect('mongodb://localhost:27017/itcast', { useNewUrlParser: true });
// 2.設(shè)計集合結(jié)構(gòu)
// 字段名稱就是表結(jié)構(gòu)中的屬性名稱
// 值
// 約束的目的是為了保證數(shù)據(jù)的完整性,不要有臟數(shù)據(jù)
// 架構(gòu)就是設(shè)置他的類型,必須要有的數(shù)據(jù)
var userSchema = new Schema({
username: {
type: String,
required: true //必須有不能為空
},
passworld: {
type: String,
required: true
},
email: {
type: String,
default:寫什么都可以//default表示默認(rèn)的
enum:[0,1]//這個表示可選的必須在這兩個中選擇一個
}
})
// 3.將文檔結(jié)構(gòu)發(fā)布為模型
// mongoose.model()方法就是用來將一個架構(gòu)發(fā)布為model
// 第一個參數(shù):傳入一個一個大寫名詞單數(shù)字符串用來表示你的數(shù)據(jù)庫名稱
// mongoose會自動將大寫名詞的字符串生成小寫復(fù)數(shù)的集合名稱
// 例如這里的User最終會變?yōu)閡sers集合名稱
// 第二個參數(shù):模型構(gòu)造函數(shù)
var User = mongoose.model('User', userSchema); //第一個參數(shù)是字符串,第二個參數(shù)是一個架構(gòu)
// 4.當(dāng)我們有了模型構(gòu)造韓素華之后,就可以使用這個構(gòu)造函數(shù)對users集合中的數(shù)據(jù)進(jìn)行(增刪改查)
增加數(shù)據(jù)
var admin = new User({
username: 'admin',
passworld: '123456',
email: 'admin@admin.com'
});
admin.save(function(err, ret) {//里面的兩個方法用來查看是否將數(shù)據(jù)存進(jìn)去
if (err) {
console.log('失敗');
} else {
console.log('成功');
console.log(ret);
}
})
一次性寫法:
new student(req.query).save(function(err, user) {
if (err) {
return next(err)
}
res.status(200).json({
err_code: 0,
message: 'OK',
user: user
})
})
查詢數(shù)據(jù)
? 查詢所有數(shù)據(jù):
// ***********************
// #region 查詢數(shù)據(jù)所有數(shù)據(jù)
// ***********************
User.find(function(err, ret) {
if (err) {
console.log('失敗');
} else {
console.log(ret);
}
})
按照條件查詢數(shù)據(jù)(查詢出來的是數(shù)組里面存放的是對象):
User.find({
username: '張三'
//年齡大于18去API查
}, function(err, ret) {
if (err) {
console.log('失敗');
} else {
console.log(ret);
}
})
按照條件查詢數(shù)據(jù)(查詢出來的是數(shù)據(jù)直接存放在對象中()):
User.findOne({ //如果第一個沒有參數(shù),那么查詢的就是第一個數(shù)據(jù)
username: '張三', //多個數(shù)據(jù)直接在后面跟就好了
passworld: '123456'
}, function(err, ret) {
if (err) {
console.log('失敗');
} else {
console.log(ret);
}
})
分析查詢
User.find(function(err, ret) {
if (err) {
console.log('失敗');
} else {
console.log(ret);
}
}).limit(1)//表示輸出第一行數(shù)據(jù)
user.getIndexes();
刪除數(shù)據(jù)
根據(jù)條件刪除所有
User.remove({
username: '張三'
}, function(err, ret) {
if (err) {
console.log('失敗');
}
console.log('成功');
console.log(ret);//所有的張三都刪除了
})
根據(jù)條件刪除一個
Model.findOneAndRemove(conditions,[options],[callback])
根據(jù)id刪除一個
Model.findByIdAndRemove(id,[options],[callback])
更新數(shù)據(jù)
根據(jù)條件更新所有:
Model.update(conditions,doc,[options],[callback])
根據(jù)指定條件更新一個:
Model.findOneAndUpdate([conditions],[update],[options],[callback])
根據(jù)id更新一個
// 第一個參數(shù)是他的MongoDB的id,第二個參數(shù)是你所想要修改的值,第三個是回調(diào)函數(shù)是否成功的
User.findByIdAndUpdate('5e0749619ca65b30b05a69ca', {
passworld: '123'
}, function(err, ret) {
if (err) {
console.log('失敗');
} else {
console.log('成功');
}
})
Mongodb 對內(nèi)嵌數(shù)組的增刪改查操作
先做一個初始化,設(shè)置一個User類,其初始數(shù)據(jù)如下:
{ arr: [ 1, 2 ],
_id: 5ac5ee12a79131259413c40f,
name: 'scy',
__v: 0 }
每次以初始數(shù)據(jù)為基,進(jìn)行操作。
1、向內(nèi)嵌數(shù)組添加數(shù)據(jù)
使用操作符 $push,向數(shù)組末尾添加數(shù)據(jù) ,可重復(fù)
//第一個參數(shù)是匹配條件 第二個參數(shù)是具體操作
User.update({name:"scy"},{$push:{"arr":3}});//向user里面的arr末尾追加元素3
結(jié)果如下:
{ arr: [ 1, 2, 3 ],
_id: 5ac5f0d3db343b1888a8969d, name: 'scy',__v: 0 }
一次添加多個數(shù)據(jù)
User.update({name:"scy"},{$push:{"arr":{$each:[2,3]}}});
router.get('/tijiao', function(req, res, next) {
student1.find(function(err, ret) {
if (err) {
console.log('失敗');
} else {
var now = new Date();
var nowStr = now.toLocaleString('chinese', { hour12: false });
req.query.data = nowStr;
req.query.changdu = ret.length + 1
new student1(req.query).save(function(err, ret) { //里面的兩個方法用來查看是否將數(shù)據(jù)存進(jìn)去
if (err) {
console.log('失敗');
} else {
console.log(req.query);
console.log(ret._id);
//注意就是這里將上一個''引號可以轉(zhuǎn)換
req.query.sid = ret._id + '';
student.update({ _id: req.query.id }, { $push: { 'shuzu': req.query } }, function(err, ret) {
if (err) {
console.log('失敗');
} else {
console.log('成功');
}
})
res.status(200).json({
err_code: 0,
message: 'OK',
ret: ret,
})
}
})
}
})
})
2、刪除內(nèi)嵌數(shù)組指定數(shù)據(jù)
注意添加的時候加一個''引號這樣可以將id轉(zhuǎn)為字符串
使用操作符 $pull
//刪除arr所有數(shù)據(jù)為2的元素
User.update({name:"scy"},{$pull:{"arr":2}});
執(zhí)行結(jié)果:
{ arr: [ 1 ], _id: 5ac5f39fdad94e23e8de9aee, name: 'scy', __v: 0 }
如果數(shù)組元素是對象,可以根據(jù)對象屬性操作:
{
name:"scy",
mArray:[{age:13,weight:50},{age:13,weight:30}]
}
User.update({name:"scy"},{$pull:{"mArray":{"weight":30}}});//刪除所有weight屬性值為30的對象
MongoDB,從數(shù)組中刪除對象
{
_id: 5150a1199fac0e6910000002,
name: 'some name,
items: [{
id: 23,
name: 'item name 23'
},{
id: 24,
name: 'item name 24'
}]
}
刪除代碼
User.update(
{'_id': ObjectId("5150a1199fac0e6910000002")},
{ $pull: { "items" : { id: 23 } } }
);
3、修改內(nèi)嵌數(shù)組指定數(shù)據(jù)
-
數(shù)據(jù)截圖:
[圖片上傳失敗...(image-614047-1601889185798)]
-
我想更新arr_1數(shù)組中,a = 1 的對象,更新為 {a:11,b:12} 運(yùn)行更新代碼,如下:
[復(fù)制代碼](javascript:void(0);)
[db.nestedUpdate.updateMany({ 'arr_1.a': 1 }, { $set: { 'arr_1.$.a': 11, 'arr_1.$.b': 12, } }) 也可以:繼續(xù)存 $set: { "shuzu.$.sun8": [{ sun9: req.query.xuehao, sun10: req.query.xuehao, sun11: req.query.xuehao, }, { sun9: req.query.xuehao, sun10: req.query.xuehao, sun11: req.query.xuehao, sun12: '7', }] }復(fù)制代碼](javascript:void(0);)
我暫時還沒找到能批量修改數(shù)組元素的方法
1
3、修改內(nèi)嵌數(shù)組指定數(shù)據(jù)
我暫時還沒找到能批量修改數(shù)組元素的方法
//將數(shù)組里面的第一個元素1修改為3
User.update({"arr":{$all:[1]}},{$set:{"arr.$":2}});
//也可以根據(jù)下標(biāo)
User.update({$set:{"arr.1":22}});//將arr下標(biāo)為1的元素修改為22
如果數(shù)組的元素是對象,如下:
1
2
如果數(shù)組的元素是對象,如下:
{
name:"scy",
mArray:[{age:13,weight:50},{age:13,weight:30}]
}
修改操作如下:
User.update({"mArray.age":13},{$set:{"mArray.$.age":22}});//將第一個age為13的值修改為22
//還可以這樣 mArray.1.age 其中1是下標(biāo)
User.update({$set:{"mArray.1.age":22}});//將arr第二個元素對象的age改為22
批量修改內(nèi)嵌數(shù)組對象
//computer1數(shù)據(jù)表
//data.$[].network數(shù)組下面的數(shù)據(jù)
computer1.update({'roomNumber': req.query.w}, {$set: {'data.$[].network': 10}}, {multi: true},function(a,s){
console.log(a);
console.log(s);
})
4、查詢內(nèi)嵌數(shù)組并返回指定的數(shù)據(jù)
使用$size 返回指定數(shù)組長度的數(shù)據(jù)
//$size限制比較大 下面表示查詢數(shù)組長度為2的數(shù)據(jù)
User.find({arr:{$size:2}})
$slice,這個操作符還是比較強(qiáng)大的適合查詢數(shù)組中的數(shù)據(jù)
//匹配到的user 將其數(shù)組截取第一個返回 如[1,1,2]返回[1]
User.findOne({name:"scy"},{arr:{$slice:1}});
//將匹配到的user的數(shù)組 截取返回后面兩個元素 如[1,1,2]返回[1,2]
User.findOne({name:"scy"},{arr:{$slice:-2}});
//從數(shù)組的下表為1的元素開始 返回兩個 如[1,3,2]返回[3,2]
User.findOne({name:"scy"},{arr:{$slice:[1,2]}});
$elemMatch查詢的是某一個數(shù)據(jù)
用法如下:
User.findOne({name:"scy"},{arr:{$elemMatch:{key:val}});
總的代碼案例如下:
在當(dāng)前的目錄下的demo.js文件下
嵌套管道查詢
const SurveySchema = new Schema({
_id:{ type: Schema.ObjectId, auto: true },
name: String,
enabled: {type: Boolean, Default: true},
created_date:{type: Date, Default: Date.now},
company: {type: Schema.Types.ObjectId, ref: 'Company'},});
const GroupSchema = new Schema({
_id:{ type: Schema.ObjectId, auto: true },
name: String,
order: String,
created_date:{type: Date, Default: Date.now},
questions: [{type: Schema.Types.ObjectId, ref: 'Question'}],
survey: {type: Schema.Types.ObjectId, ref: 'Survey'}
});
const ResponseSchema = new Schema({
_id:{ type: Schema.ObjectId, auto: true },
response_text: String,
order: String,
created_date:{type: Date, Default: Date.now},
question:{type: Schema.Types.ObjectId, ref: 'Question'}
});
Survey.aggregate([
{ $match: {} },
{ $lookup: {
from: 'groups',
localField: '_id',
foreignField: 'survey',
as: 'groupsofquestions',
}},
{ $unwind: {
path: "$groupsofquestions",
preserveNullAndEmptyArrays: true
}},
{ $lookup: {
from: 'questions',
localField: 'groupsofquestions._id',
foreignField: 'group',
as: 'questionsofgroup',
}},
{ $lookup: {
from: 'response',
localField: 'questionsofgroup._id',
foreignField: 'question',
as: 'responses',
}},
{ $group: {
_id: "$_id",
name: {$first: "$name"},
groups: {$push: {
id: "$groupsofquestions._id",
name: "$groupsofquestions.name",
questions: "$questionsofgroup",
reponses: "$responses"
}}
}}
])
aggregate()
語 法 \color{red}{語法}語法
db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION);
1
數(shù) 據(jù) \color{red}{數(shù)據(jù)}數(shù)據(jù)
數(shù)據(jù)使用菜鳥教程的數(shù)據(jù)啦????
/* 1 */
{
"_id" : ObjectId("5e86e29788e64443e448dfc0"),
"title" : "MongoDB Overview",
"description" : "MongoDB is no sql database",
"by_user" : "runoob.com",
"url" : "http://www.runoob.com",
"tags" : [
"mongodb",
"database",
"NoSQL"
],
"likes" : 100
}
/* 2 */
{
"_id" : ObjectId("5e86e2ad88e64443e448dfd2"),
"title" : "NoSQL Overview",
"description" : "No sql database is very fast",
"by_user" : "runoob.com",
"url" : "http://www.runoob.com",
"tags" : [
"mongodb",
"database",
"NoSQL"
],
"likes" : 10
}
/* 3 */
{
"_id" : ObjectId("5e86e2bc88e64443e448dfd7"),
"title" : "Neo4j Overview",
"description" : "Neo4j is no sql database",
"by_user" : "Neo4j",
"url" : "http://www.neo4j.com",
"tags" : [
"neo4j",
"database",
"NoSQL"
],
"likes" : 750
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344
管 道 操 作 符 \color{red}{管道操作符}管道操作符
| 操作符 | 含義 |
|---|---|
| $group | 將collection中的document分組,可用于統(tǒng)計結(jié)果 |
| $match | 過濾數(shù)據(jù),只輸出符合結(jié)果的文檔 |
| $project | 修改輸入文檔的結(jié)構(gòu)(例如重命名,增加、刪除字段,創(chuàng)建結(jié)算結(jié)果等) |
| $sort | 將結(jié)果進(jìn)行排序后輸出 |
| $limit | 限制管道輸出的結(jié)果個數(shù) |
| $skip | 跳過制定數(shù)量的結(jié)果,并且返回剩下的結(jié)果 |
| $unwind | 將數(shù)組類型的字段進(jìn)行拆分 |
表 達(dá) 式 操 作 符 \color{red}{表達(dá)式操作符}表達(dá)式操作符
| 操作符 | 含義 | 實(shí)例 |
|---|---|---|
| $sum | 計算總和,{$sum: 1}表示返回總和×1的值(即總和的數(shù)量),使用{$sum: '$制定字段'}也能直接獲取制定字段的值的總和 |
db.collection.aggregate([{$group : {_id : "$by_user", content_sum : {$sum : "$likes"}}}]) |
| $avg | 平均值 | db.collection.aggregate([{$group : {_id : "$by_user", content_sum : {$avg : "$likes"}}}]) |
| $min | 獲取集合中所有文檔對應(yīng)值得最小值 | db.collection.aggregate([{$group : {_id : "$by_user", content_sum : {$min : "$likes"}}}]) |
| $max | 獲取集合中所有文檔對應(yīng)值得最大值 | db.collection.aggregate([{$group : {_id : "$by_user", content_sum : {$max : "$likes"}}}]) |
| $push | 在結(jié)果文檔中插入值到一個數(shù)組中 | db.collection.aggregate([{$group : {_id : "$by_user", url : {$push : "$url"}}}]) |
| $addToSet | 在結(jié)果文檔中插入值到一個數(shù)組中,但不創(chuàng)建副本 | db.collection.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}]) |
| $first | 根據(jù)資源文檔的排序獲取第一個文檔數(shù)據(jù) | db.collection.aggregate([{$group : {_id : "$by_user", url : {$first : "$url"}}}]) |
| $last | 根據(jù)資源文檔的排序獲取最后一個文檔數(shù)據(jù) | db.collection.aggregate([{$group : {_id : "$by_user", url : {$last : "$url"}}}]) |
具 體 例 子 \color{skyblue}{具體例子}具體例子
-
$group
-
簡單闡述
//將document分組,用作統(tǒng)計結(jié)果 db.collection.aggregate([ // aggregate方法接收的是一個數(shù)組 { $group: { // _id字段表示要基于哪個字段來進(jìn)行分組(即制定字段值相同的為一組) // $by_user表示要基于$by_user字段來進(jìn)行分組 _id: '$by_user', // content_sum字段的值$sum: 1表示的是獲取滿足by_user字段相同的這一組的數(shù)量乘以后面給定的值(本例為1,那么就是同組的數(shù)量)。 content_sum: {$sum: 1} } } ]) 123456789101112 -
具體案例
通過以上集合計算每個作者所寫的文章數(shù)(通過字段
by_user字段對數(shù)據(jù)進(jìn)行分組,并計算by_user字段相同值的總和),使用aggregate()計算結(jié)果如下:router.get('/getInfo',async(req, res)=>{ let data=await Content.aggregate([ { $group:{ _id:'$by_user', content_sum:{$sum:1} } } ]) res.json({data}) }) 1234567891011在這里插入圖片描述
-
-
$match
獲取
likes的值在50-200之間的數(shù)據(jù):router.get('/getInfo', async (req, res) => { let data = await Content.aggregate([{ $match: { likes: { $gt: 50, $lte: 200 } } }, { $group: { _id: '$_id', content_sum: { $sum: 1 } } } ]) res.json({ data }) }) 12345678910111213141516171819202122在這里插入圖片描述從圖中可以看出
likes的值在50-200之間的數(shù)據(jù)只有1條,現(xiàn)在我們只知道這條數(shù)據(jù)的_id,如果想知道這條數(shù)據(jù)的具體信息時應(yīng)該如何操作呢?上面的表格中提到$project修改輸入文檔的結(jié)構(gòu)(例如重命名,增加、刪除字段,創(chuàng)建結(jié)算結(jié)果等),所以一起來看看吧?????? -
$project
router.get('/getInfo', async (req, res) => { let data = await Content.aggregate([ { $match: { likes: { $gt: 50, $lte: 200 } } }, { //以下的值可以寫$+字段,也可以使用0 和1來表示,若要顯示字段則為1,否則為0 //$project:{_id:'$_id',title:"$title",description:"$description",by_user:"$by_user",url:'$ulr',tags:'$tags',likes:'$likes'} $project:{_id:1,title:1,description:1,by_user:1,url:1,tags:1,likes:1} } ]) res.json({ data }) }) 12345678910111213141516在這里插入圖片描述 -
以上3個操作符的綜合使用
如果想拿到所有
likes>=10的document的by_user字段可以把管道搭配起來用:router.get('/getInfo', async (req, res) => { let data = await Content.aggregate([{ $match: { likes: { $gt: 10 } } }, // 注意$project與$group的順序,換位置后數(shù)據(jù)為空 { $project: { _id: 0, //_id不顯示 by_user: 1 //by_user顯示 } }, { $group: { _id: null, gameName: { $push: '$by_user' } } } ]) res.json({ data }) }) 12345678910111213141516171819202122232425262728在這里插入圖片描述 -
$sort
-
根據(jù)
likes進(jìn)行降序排序router.get('/getInfo', async (req, res) => { let data = await Content.aggregate([ { $project: { _id: 1, by_user: 1, title: 1, title: 1, description: 1, url: 1, tags: 1, likes: 1 } }, { $sort: { likes: -1 } }, ]) res.json({ data }) }) 12345678910111213在這里插入圖片描述 -
根據(jù)
likes進(jìn)行升序排序router.get('/getInfo', async (req, res) => { let data = await Content.aggregate([ { $project: { _id: 1, by_user: 1, title: 1, title: 1, description: 1, url: 1, tags: 1, likes: 1 } }, { $sort: { likes: 1 } }, ]) res.json({ data }) }) 12345678910111213在這里插入圖片描述
-
-
skip
router.get('/getInfo', async (req, res) => { let data = await Content.aggregate([ { $project: { _id: 1, by_user: 1, title: 1, title: 1, description: 1, url: 1, tags: 1, likes: 1 } }, { $sort: { likes: 1 } }, { $skip:1 }, { $limit:1 } ]); res.json({ data }) }) 1234567891011121314151617181920在這里插入圖片描述 -
$unwind
$unwind管道以document中的數(shù)組類型的字段進(jìn)行拆分,每條包含數(shù)組中的一個值。
比如拆分
likes:10這條數(shù)據(jù),先來看看整體數(shù)據(jù)信息吧:{ "_id" : ObjectId("5e86e2ad88e64443e448dfd2"), "title" : "NoSQL Overview", "description" : "No sql database is very fast", "by_user" : "runoob.com", "url" : "http://www.runoob.com", "tags" : [ "mongodb", "database", "NoSQL" ], "likes" : 10 } 12345678910111213在
tags數(shù)組中有3條數(shù)據(jù),所以拆分后會顯示3條數(shù)據(jù),看看具體實(shí)現(xiàn)吧:router.get('/getInfo', async (req, res) => { let data = await Content.aggregate([ { $match: { likes: 10 } }, { $unwind:'$tags' }, { $project: { _id: 1, by_user: 1, title: 1, title: 1, description: 1, url: 1, tags: 1, likes: 1 } }, ]) res.json({ data }) }) 123456789101112131415161718在這里插入圖片描述



