node.js連接mongodb數據庫

第一種

安裝

在命令行中下載mongoose

npm install mongoose --save

引入mongoose并連接數據庫

// 引入第三方包mongoose
const mongoose = require('mongoose');
// 要管理員的賬號和密碼才能進行數據庫操作
// mongoose.connect('mongodb://user:pass@localhost:port/database')
// user表示用戶名,pass表hi是密碼,port表示數據庫的端口mongodb的默認端口27017,database表示數據庫的名字
// 連接數據庫
mongoose.connect('mongodb://127.0.0.1/blog', {
    useUnifiedTopology: true,
    useNewUrlParser: true
}).then(() => { //這里面的then()方法是如果成功輸出成功,如果失敗在catch()方法里面輸出失敗
    console.log('數據庫成功');
}).catch(() => {
    console.log('失敗');
});

配置Schema(通過require獲取)

就是

// 1.引入mongoose模塊
const mongoose = require('mongoose');
// 2.創(chuàng)建文章集合類型  定義一個Schema  Schema里面的對象和數據庫表里面的字段需要一一對應
const articleSchema = new mongoose.Schema({
    title: {
        type: String,
        maxlength: 20, //最大長度
        minlength: 4, //最小長度
        required: [true, '請?zhí)顚懳恼聵祟}'] //第一個參數是告訴這個是必填字段匈辱,第二個參數表示錯誤信息
    },
    author: {
        type: mongoose.Schema.Types.ObjectId, //要將文章中的作者和用戶中的作者進行關聯
        ref: 'User', //這個屬性就是用來將文章集合和用戶集合進行關聯’User‘就是集合的名字
        required: [true, '請傳遞作者'],
    },
    publishDate: {
        type: Date,
        default: Date.now,
    },
    cover: {
        type: Number,
        default: 1      //表示默認參數涡上,如果不寫,那么數據庫就會默認為1
    },
    content: {
        type: String
    }
});
// 3.根據規(guī)則常見集合,定義數據庫模型  操作數據庫
// model 里面的第一個參數要注意首字母要大寫  2,要和數據庫表(集合名稱對應)
// 第二個參數要和Schema上面的一樣
const Article = mongoose.model('Article', articleSchema);
//Article會默認和數據庫中的Articles進行連接,我們也可以指定數據名詞高镐,設置第三個參數就OK了
//這樣那么Article就和artes建立了連接
//const Article = mongoose.model('Article', articleSchema,'artes');
// 4.將集合規(guī)則作為模板成員進行導出
module.exports = {
    Article
}

模塊化配置

就是通過導入導出的方式來進行模塊化

const mongoose = require('mongoose');
mongoose.connect('mongodb://127.0.0.1/blog', {
    useUnifiedTopology: true,
    useNewUrlParser: true
}).then(() => { //這里面的then()方法是如果成功輸出成功,如果失敗在catch()方法里面輸出失敗
    console.log('數據庫成功');
}).catch(() => {
    console.log('失敗');
});
// 導出數據
module.exports=mongoose;

引入數據庫

// 1.引入mongoose模塊
const mongoose = require('mongoose');
// 2.創(chuàng)建文章集合類型
const articleSchema = new mongoose.Schema({
    title: {
        type: String,
        maxlength: 20, //最大長度
        minlength: 4, //最小長度
        required: [true, '請?zhí)顚懳恼聵祟}'] //第一個參數是告訴這個是必填字段一汽,第二個參數表示錯誤信息
    },
    author: {
        type: mongoose.Schema.Types.ObjectId, //要將文章中的作者和用戶中的作者進行關聯
        ref: 'User', //這個屬性就是用來將文章集合和用戶集合進行關聯’User‘就是集合的名字
        required: [true, '請傳遞作者'],
    },
    publishDate: {
        type: Date,
        default: Date.now,
    },
    cover: {
        type: String,
        default: null
    },
    content: {
        type: String
    }
});
// 3.根據規(guī)則常見集合
const Article = mongoose.model('Article', articleSchema);
// 4.將集合規(guī)則作為模板成員進行導出
module.exports = {
    Article
}

操作那個數據庫引入就可以了

require('./')
操作添加避消,刪除,修改

預定義修飾符

lowercase召夹、uppercase岩喷、trim

mongoose提供了預定義模式修飾符,可以對我們的數據進行一些格式化

// 1.引入mongoose模塊
const mongoose = require('mongoose');
// 2.創(chuàng)建文章集合類型
const articleSchema = new mongoose.Schema({
    title: {
        type: String,
        maxlength: 20, //最大長度
        minlength: 4, //最小長度
        required: [true, '請?zhí)顚懳恼聵祟}'], //第一個參數是告訴這個是必填字段监憎,第二個參數表示錯誤信息
        trim:true           //表示的是如果用戶輸入的數據兩邊有空格可以通過這個方法取消空格
    }
});

自定義修飾符Getters與Setters

除了mongoose內置的修飾符以外纱意,我們還可以通過set(建議使用)修飾符在增加數據的時候對數據進行格式化

也可以通過get(不建議使用)在實力獲取數據的時候對數據進行格式化。

這是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í)顚懳恼聵祟}'], //第一個參數是告訴這個是必填字段鲸阔,第二個參數表示錯誤信息
        trim:true           //表示的是如果用戶輸入的數據兩邊有空格可以通過這個方法取消空格
        pic:{
            type:String,
            set(parmas){    //增加數據的時候對pic字段進行處理
                    //parmas可以獲取pic的值偷霉、返回的數據就是pic在數據庫中實際保存的值
                    /**
                    *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://,所以需要進行自定義設置
    }
});

這是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í)顚懳恼聵祟}'], //第一個參數是告訴這個是必填字段类少,第二個參數表示錯誤信息
        trim:true           //表示的是如果用戶輸入的數據兩邊有空格可以通過這個方法取消空格
        name:{
        type:String,
        get(params){
                return "a001"+params    //表示的是在獲取數據的時候添加一個a001(只有同過什么.什么添加的時候)
            }
        }
    }
});

Mongoose的索引

索引是對數據庫表中一列或多列的值進行排序的一種結構,可以讓我們查詢數據庫變得更快渔扎,MONGODB的索引幾乎與傳統(tǒng)的關系型數據庫一模一樣硫狞,這其中也包括了一些基礎的查詢優(yōu)化技巧。

mongoose中除了以前創(chuàng)建索引的方式晃痴,我們也可以在定義Schema的時候指定創(chuàng)建索引残吩。

// 2.創(chuàng)建文章集合類型  定義一個Schema  Schema里面的對象和數據庫表里面的字段需要一一對應
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內置的CURD方法

[圖片上傳失敗...(image-4b0014-1601889185797)]

就是有的搜索時finByID我們也可以根據屬性來自定義一個

const articleSchema = new mongoose.Schema({
    title: {
        type: String,
        maxlength: 20, //最大長度
        minlength: 4, //最小長度
        required: [true, '請?zhí)顚懳恼聵祟}'] //第一個參數是告訴這個是必填字段倘核,第二個參數表示錯誤信息
    },
    sn:{
        
    },
    content: {
        type: String
    }
});
//靜態(tài)方法(要加一個statics)
articleSchema.statics.findBySn=function(sn,cb){
    this.find({"sn":sn},function(err,docs){
        cd(err,docs);
    })
}

//實例方法(基本沒用)
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',(){})來查詢數據

// 實例方法
//user.print();

數據校驗

這是在Schema里面

required:表示這個數據必須傳入
max:用于Number類型數據泣侮,最大值
min:用于Number類型數據,最小值
enum:枚舉類型紧唱,要求數據必須滿足枚舉值   enum:['0','1','2']注意它使用在String類型中的
match:增加的數據必須符合match(正則)的規(guī)則 注意它使用在String類型中的
maxlenth:最大長度
minlength:最小長度
default:表示默認值

自定義數據校驗

const articleSchema = new mongoose.Schema({
    title: {
        type: String,
        maxlength: 20, //最大長度
        minlength: 4, //最小長度
        required: [true, '請?zhí)顚懳恼聵祟}'] //第一個參數是告訴這個是必填字段活尊,第二個參數表示錯誤信息
    },
    content: {
        type: String,
        //自定義數據校驗  任意的類型里面
        validate:function(sn){
            return sn.length>=10;
        }
    }
});

**mongoose中使用aggregate聚合管道(后期可以在看一下)

都可以寫多次

$project(篩選指定的列)

修改文檔結構,可以用來重命名漏益,增加或刪除文檔中的字段酬凳。

要求查找order只返回文檔中的teade_no和all_price字段(order表示數據表)

order.aggregate([   //每一個管道是一個對象,對象里面實現具體的功能
    {
        $project:{teade_no:1,all_price1}
    }
])

$match(過濾)

作用:用于過濾文檔遭庶,用法類似于find()方法中的參數宁仔。

order.aggregate([   //每一個管道是一個對象,對象里面實現具體的功能
    {
        $project:{teade_no:1,all_price1}  
    },
    {
    $match:{"all_price":{$gte:90}}  //這個意思時查找總價格大于90的數據
    }
])

$group???沒懂

將集合中的文檔進行分組峦睡,可用于統(tǒng)計結果

統(tǒng)計每個訂單的訂單數量翎苫,按照訂單號分組

order.aggregate([   //每一個管道是一個對象,對象里面實現具體的功能
    {
        $group:{_id:"$order_id",total:{$sum:1}}
    }
])

$sort(排序)

將集合文檔進行排序

order.aggregate([   //每一個管道是一個對象榨了,對象里面實現具體的功能
    {
        $project:{teade_no:1,all_price1}  
    },
    {
    $match:{"all_price":{$gte:90}}  //這個意思時查找總價格大于90的數據
    },
    {
       $sort:{"all_price":-1}  //以 all_price進行排序  -1降序  1升序
    }
])

$limit(查幾條數據)

order.aggregate([   //每一個管道是一個對象煎谍,對象里面實現具體的功能
    {
        $project:{teade_no:1,all_price1}  
    },
    {
    $match:{"all_price":{$gte:90}}  //這個意思時查找總價格大于90的數據
    },
    {
       $sort:{"all_price":-1}  //以 all_price進行排序  -1降序  1升序
    },
    {
        $limit:1        //表示只返回一條數據
    }
])

$skip (跳過幾條數據)

order.aggregate([   //每一個管道是一個對象,對象里面實現具體的功能
    {
        $project:{teade_no:1,all_price1}  
    },
    {
    $match:{"all_price":{$gte:90}}  //這個意思時查找總價格大于90的數據
    },
    {
       $sort:{"all_price":-1}  //以 all_price進行排序  -1降序  1升序
    },
    {   
        $skip:1     //跳過幾條數據
    }
])

$unwind

$unwind管道以document中的數組類型的字段進行拆分龙屉,每條包含數組中的一個值呐粘。

比如拆分likes:10這條數據满俗,先來看看整體數據信息吧:

{
    "_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
  })
})
img

$lookup(表關聯操作)

order.aggregate([   //每一個管道是一個對象,對象里面實現具體的功能
    {
        $lookup:{
            from:"order_item",                      //就是你這個表要和那個表進行關聯
            localField:"order_id",                  //表示你order表關聯的字段
            foreignField:"order_id",                //表示你order_item表與order表關聯的id
            as:"items"                              //as表示你要關聯的數據要放在哪里order的那個屬性里面
        }
    }
])



//想獲取的這樣的數據
[
    {
        Order_id:"",
        Trade_no:"",
        items:[
            {
                title:"鼠標",
                name:"名字"
            },
            {
                title:"鍵盤",
                name:"名字"
            }
        ]
    }
]
//要觀察誰關聯誰
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: "商品鼠標1", price: 50, num: 1 },
  { order_id: "1", title: "商品鼠標2", price: 50, num: 1 },
  { order_id: "1", title: "商品鼠標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',         // 要關聯的表
            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',         // 要關聯的表
            localField:'order_id',     //order表中的order_id
            foreignField:'order_id',   // order_item表中的order_id
            as:'items'
        }
    }    
])

查詢一個表作岖,找出商品名稱是酸奶的商品唆垃,酸奶這個商品對應的訂單的訂單號以及訂單總價格。

//先查一個表痘儡,然后獲取出數據辕万,再通過獲取的數據查下一個表
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 )
    })
}

多個表的關聯存儲

這里就是通過輸入id來進行關聯

[圖片上傳失敗...(image-b2baf1-1601889185798)]

//article.js文件
// 文章表渐尿,表結構
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:'國內行文',
    descripton:'國內行文'
})
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:'習近平訪問',//國際新新聞
    cid:'查找國際新聞的id與他關聯',
    author_id:'獲取用戶的id與他關聯',//用戶的id
    author_name:"獲取用戶的名與之關聯",
    descripton:'我的描述’',
    content:'這里面時內容詳情'
})
cate.save();

mongoose實現多個表查詢Populate

mongoose使用關聯查詢的時候,你首先要知道主鍵與外鍵

要使用他之前要在Schema里面定義ref那個表的key有外鍵那個就是用ref

const articleSchema = new mongoose.Schema({
    author: {
        type: mongoose.Schema.Types.ObjectId, //要將文章中的作者和用戶中的作者進行關聯
        ref: 'User', //這個屬性就是用來將文章集合和用戶集合進行關聯’User‘就是集合的名字
        required: [true, '請傳遞作者'],
    }
});


//查詢的方法

// 注意要是用populate需要引入用到的Moudel
//說建議用聚合管道查詢
    let articles = await pagination(Article)//pagination分頁矾瑰,
        .find()//查詢
        .page(page)//客戶端傳遞過來的頁碼
        .size(2)//顯示幾個
        .display(3)//最多
        .populate("author") //populate('')這個方法里面存放的就是你要查詢的字段信息
        .exec();

增加數據

//實例化Model   通過實例化User 的Molde創(chuàng)建添加數據
var admin = new User({
    username: 'admin',
    passworld: '123456',
    email: 'admin@admin.com'
});
admin.save(function(err, ret) {//里面的兩個方法用來查看是否將數據存進去
    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
        })
    })

查詢數據

? 查詢所有數據:

// ***********************
// #region 查詢數據所有數據
// ***********************
User.find(function(err, ret) {
    if (err) {
        console.log('失敗');
    } else {
        console.log(ret);
    }
})

按照條件查詢數據(查詢出來的是數組里面存放的是對象):

User.find({
    username: '張三'
    //年齡大于18去API查
}, function(err, ret) {
    if (err) {
        console.log('失敗');
    } else {
        console.log(ret);
    }
})

按照條件查詢數據(查詢出來的是數據直接存放在對象中()):

User.findOne({ //如果第一個沒有參數,那么查詢的就是第一個數據
    username: '張三', //多個數據直接在后面跟就好了
    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)//表示輸出第一行數據
user.getIndexes();

查詢方法

mongoose查詢使用最基礎的方法就是find砖茸、findOne方法,前者查詢所有滿足條件的值殴穴,后者取滿足條件的某一個值渔彰。

2、查詢條件

mongoose查詢條件其實就是在find方法的基礎上添加mongodb條件操作符推正,如Thing.find().gt('age', 21)就等同于Thing.find({age: {$gt: 21}})恍涂,mongodb條件操作符如下:

    $or    或關系db.collection_name.find({$or: [{key1: value1}, {key2: value2}]})

  $nor    或關系取反 

  $gt    大于

  $gte    大于等于

  $lt     小于

  $lte     小于等于

  $ne            不等于

  $in             在多個值范圍內

  $nin           不在多個值范圍內

  $all            匹配數組中多個值

  $regex  正則,用于模糊查詢

  $size   匹配數組大小

  $maxDistance  范圍查詢植榕,距離(基于LBS)

  $mod     取模運算

  $near   鄰域查詢再沧,查詢附近的位置(基于LBS)

  $exists    字段是否存在

  $elemMatch  匹配內數組內的元素

  $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寝衫、填充對象

查詢對象時顷扩,對象中存在其他對象的引用,查詢出來的引用對象默認是顯示引用對象的id慰毅,如果需要引用對象的其他屬性就需要使用populate方法填充引用對象隘截。

如果對以上知識點不太了解可以參考:

查詢實例

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、深層屬性查詢

有些對象結構比較復雜汹胃,屬性可能存在多層嵌套關系婶芭,有時需要通過對象屬性下屬的屬性查詢對象,如通過content的label的值查詢Comment

Comment.find({'content.label': value}, function (err, comment) {
    console.log(comment)
})

2着饥、二維數組查詢

如果二維數組結構為[[]]犀农,這樣的數組是可以查詢,但是填充數組里對象時會有問題

Comment.find({'points': value}).populate('points').exec(function (err, comment) {
    console.log(comment) // 無法填充points
})

所以需要填充二維數組里的對象時宰掉,不能使用這種結構呵哨,而應該如schema.js中一樣赁濒,將里面的數組先作為對象保存

Comment.find({'points': value}).populate('points.point').exec(function (err, comment) {
    console.log(comment) // 無法填充points
})

3、循環(huán)填充

結構如Point孟害,讀取point時拒炎,需要填充children,而childern的childern也需要填充纹坐,使用populate只能填充當前的childern枝冀,在schema.js添加:

PointSchema.pre('find', function(next) {
  this.populate('children')
  next()
})

這樣每次查詢時舞丛,自動為point填充childern

4耘子、多表聯合查詢

mongoose其實沒有多表聯合查詢的方法,不過我們可以通過多次查詢來實現球切。
通過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)
    })
})

有時我們也需要對取出來的數據進行再次過濾,而不是通過查詢語句查詢
通過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
        })
    })
})

刪除數據

根據條件刪除所有

User.remove({
    username: '張三'
}, function(err, ret) {
    if (err) {
        console.log('失敗');
    }
    console.log('成功');
    console.log(ret);//所有的張三都刪除了

})

根據條件刪除一個

Model.findOneAndRemove(conditions,[options],[callback])

根據id刪除一個

Model.findByIdAndRemove(id,[options],[callback])

刪除的方法

Model.deleteOne(id,[options],[callback])

更新數據

根據條件更新所有:

//model就是數據表鸵钝,你引入的表名
Model.update(conditions,doc,[options],[callback])

Model.updateOne(conditions,doc,[options],[callback])

根據指定條件更新一個:

Model.findOneAndUpdate([conditions],[update],[options],[callback])

根據id更新一個

// 第一個參數是他的MongoDB的id,第二個參數是你所想要修改的值,第三個是回調函數是否成功的
User.findByIdAndUpdate('5e0749619ca65b30b05a69ca', {
    passworld: '123'
}, function(err, ret) {
    if (err) {
        console.log('失敗');
    } else {
        console.log('成功');

    }
})

Mongodb 對內嵌數組的增刪改查操作

先做一個初始化糙臼,設置一個User類,其初始數據如下:

{ arr: [ 1, 2 ],
  _id: 5ac5ee12a79131259413c40f,
  name: 'scy',
  __v: 0 }

每次以初始數據為基恩商,進行操作变逃。

1、向內嵌數組添加數據

使用操作符 $push怠堪,向數組末尾添加數據 揽乱,可重復

//第一個參數是匹配條件 第二個參數是具體操作
    User.update({name:"scy"},{$push:{"arr":3}});//向user里面的arr末尾追加元素3

結果如下:

{ arr: [ 1, 2, 3 ],
  _id: 5ac5f0d3db343b1888a8969d, name: 'scy',__v: 0 }

一次添加多個數據

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) { //里面的兩個方法用來查看是否將數據存進去
                if (err) {
                    console.log('失敗');
                } else {
                    console.log(req.query);
                    console.log(ret._id);
//注意就是這里將上一個''引號可以轉換
                    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、刪除內嵌數組指定數據

注意添加的時候加一個''引號這樣可以將id轉為字符串

使用操作符 $pull

//刪除arr所有數據為2的元素
  User.update({name:"scy"},{$pull:{"arr":2}});

執(zhí)行結果:

{ arr: [ 1 ], _id: 5ac5f39fdad94e23e8de9aee, name: 'scy', __v: 0 }

如果數組元素是對象,可以根據對象屬性操作:

{
  name:"scy",
  mArray:[{age:13,weight:50},{age:13,weight:30}]
}
User.update({name:"scy"},{$pull:{"mArray":{"weight":30}}});//刪除所有weight屬性值為30的對象

MongoDB,從數組中刪除對象

{
   _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粟矿、修改內嵌數組指定數據

  1. 數據截圖:

    [圖片上傳失敗...(image-e19f7e-1601889185798)]

  1. 我想更新arr_1數組中凰棉,a = 1 的對象,更新為 {a:11,b:12} 運行更新代碼陌粹,如下:

    [
    復制代碼

    ](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',
                        }]
                    }
    

    [
    復制代碼

    ](javascript:void(0);)

我暫時還沒找到能批量修改數組元素的方法

1
3撒犀、修改內嵌數組指定數據
我暫時還沒找到能批量修改數組元素的方法

//將數組里面的第一個元素1修改為3
User.update({"arr":{$all:[1]}},{$set:{"arr.$":2}});
//也可以根據下標
User.update({$set:{"arr.1":22}});//將arr下標為1的元素修改為22

如果數組的元素是對象,如下:

1
2
如果數組的元素是對象掏秩,如下:

{
  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是下標 
User.update({$set:{"mArray.1.age":22}});//將arr第二個元素對象的age改為22

批量修改內嵌數組對象

//computer1數據表
//data.$[].network數組下面的數據
computer1.update({'roomNumber': req.query.w}, {$set: {'data.$[].network': 10}}, {multi: true},function(a,s){
            console.log(a);
            console.log(s);
            
        })

4绘证、查詢內嵌數組并返回指定的數據

使用$size 返回指定數組長度的數據

//$size限制比較大 下面表示查詢數組長度為2的數據
User.find({arr:{$size:2}})

$slice,這個操作符還是比較強大的適合查詢數組中的數據

//匹配到的user 將其數組截取第一個返回 如[1,1,2]返回[1]
User.findOne({name:"scy"},{arr:{$slice:1}});
//將匹配到的user的數組 截取返回后面兩個元素  如[1,1,2]返回[1,2]
User.findOne({name:"scy"},{arr:{$slice:-2}});
//從數組的下表為1的元素開始 返回兩個 如[1,3,2]返回[3,2]
User.findOne({name:"scy"},{arr:{$slice:[1,2]}});

$elemMatch查詢的是某一個數據

用法如下:

User.findOne({name:"scy"},{arr:{$elemMatch:{key:val}});

總的代碼案例如下:

在當前的目錄下的demo.js文件下

導出導入數據庫

首先要開啟數據庫連接通過mongod --dbpath 數據存儲目錄路徑 我的數據庫目錄地址好像在D:\mongoDB\two

然后在命令行中輸入

導出:

//-h表示主機  -d表示要導出的數據庫  -o輸出的目錄
mongodump -h (主機127.0.0.1) -d (到處的數據庫)  -o (地址)  
//例如
mongodump -h 127.0.0.1 -d  user  -o   C:\data

導入:

mongorestore -h (主機地址) -d (導入數據庫名)  導入的地址

第二種

8.MongoDB數據庫

8.1 關系型數據庫的非關系型數據庫

表就是關系

或者說表于表之間存在關系。

  • 所有的關系型數據庫都需要通過sql語言來操作
  • 所有的關系型數據庫都需要設計表結構
  • 而且數據表還支持約束
    • 唯一的
    • 主鍵
    • 默認值
    • 非空
  • 非關系型數據庫可以說非常的靈活
  • 有的非關系型數據庫就是key-value隊
  • 在mingoDB是長得最像關系型數據庫的非關系型數據庫
    • 數據庫-》數據庫
    • 數據表-》集合(數組)
    • 表記錄-》(文檔對象)
  • MongoDB不需要設計表結構
  • 也就是說你可以任意的往里面存數據哗讥,沒有結構性這么一說

8.2安裝

8.3啟動和關閉數據庫

啟動:

# mongodb 默認使用執(zhí)行 mongdb 命令所處盤符根目錄下的/data/db 作為自己的數據存儲目錄
# 啟動的時候出現問題下面這張圖的問題
#需要在第一次執(zhí)行該命令之前先手動見一個 [c,d,盤]/data/db
在cmd中輸入mongodb

[圖片上傳失敗...(image-421fc9-1601889185798)]

如果想要修改默認數據存儲目錄嚷那,可以:

mongod --dbpath=數據存儲目錄路徑

停止:

在開啟服務的控制臺,直接Ctrl+c即可停止
或者直接關閉開啟服務的控制臺也可以杆煞。

8.4連接數據庫

#該命令默認連接本機的MongoDB服務
mongo

退出連接:

#在連接狀態(tài)輸入exit退出連接
exit

8.5基本命令

  • show dbs(查看顯示所有的數據庫)
  • db (查看當前操作的數據庫)
  • use 數據庫名稱 (切換到指定數據【如果沒有會新建】)
  • 插入數據

8.6在Node中如何操作MongoDB數據

8.6.1使用官方的mongodb包來操作

https://github.com/mongodb/node-mongodb-native#installation

8.6.2使用第三方的mongodb來操作Mongodb數據庫

第三方包:Mongodb基于Mongodb官方的mongodb包再一次做了封裝

https://mongoosejs.com/

第三方包連接數據庫

安裝:

npm i mongoose
#注意先下載npm i -y (如果有就不需要下載了)然后下載mongoose第三方的包
const mongoose = require('mongoose'); //引入mongoose包
//連接MongoDB數據庫
mongoose.connect('mongodb://localhost:27017/test', { useNewUrlParser: true });
// 這句先不了解
mongoose.Promise = global.Promise;
//創(chuàng)建一個模型
// 就是在設計數據庫
// MongoDB是動態(tài)的,非常靈活,只需要在代碼中設計你的數據庫就可以了
// mongodb這個包就可以讓你的設計編寫過程變的非常簡單
const Cat = mongoose.model('Cat', { name: String });
// 實例化一個Kitty
const kitty = new Cat({ name: 'Zildjian' });
// 持久化保存kitty實例
kitty.save().then(() => console.log('meow'));

持久化存儲for:

const mongoose = require('mongoose'); //引入mongoose包
// //連接MongoDB數據庫
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數據庫的基本概念

  • 數據庫
  • 一個數據庫中有多個集合(表)
  • 一個集合中可以有多個文檔(表記錄)
  • 文檔結構靈活魏宽,沒有任何限制
  • MongoDB非常靈活众雷,不像MySQL一樣要先創(chuàng)建數據庫脐湾,表,設計表結構
    • 在這里:當你需要插入數據的時候,只需要指定往那個數據庫那個集合操作就可以
    • 一切都由MongoDB來幫你自動完成建庫建表這件事
{
    qq:{
        //users:[{'這里存的是每一條記錄'對象}],//一個對象教文檔偿渡,要有一些約定,要不然亂
        users:[
            {},
            {}
        ]
        products:[
            {name:'張三',age:15},
            {name:'李四',age:16},
            {name:'王五',age:17},
            {name:'張三123',age:18},
            ...
        ]
    },
    taobao:{
        
    },
    baidu:{
        
    }
}

mongoDB的案例構建(案例案例)

設計Scheme發(fā)布Model

這些增刪改查的方法都是根據引入的包是var mongoose = require('mongoose');方法進行的

與菜鳥聯盟的方法不同的原因是引入的包不同

var mongoose = require('mongoose');
// 獲取他的結構
var Schema = mongoose.Schema;
// 指定連接的數據庫不需要存在,當你插入第一條數據之后就會自動被創(chuàng)建出來
// 1.連接數據庫
mongoose.connect('mongodb://localhost:27017/itcast', { useNewUrlParser: true });
// 2.設計集合結構
// 字段名稱就是表結構中的屬性名稱
// 值
// 約束的目的是為了保證數據的完整性,不要有臟數據
// 架構就是設置他的類型,必須要有的數據
var userSchema = new Schema({
        username: {
            type: String,
            required: true //必須有不能為空
        },
        passworld: {
            type: String,
            required: true
        },
        email: {
            type: String,
            default:寫什么都可以//default表示默認的
            enum:[0,1]//這個表示可選的必須在這兩個中選擇一個
        }
    })
    // 3.將文檔結構發(fā)布為模型
    // mongoose.model()方法就是用來將一個架構發(fā)布為model
    // 第一個參數:傳入一個一個大寫名詞單數字符串用來表示你的數據庫名稱
    //             mongoose會自動將大寫名詞的字符串生成小寫復數的集合名稱
    //              例如這里的User最終會變?yōu)閡sers集合名稱
    //              第二個參數:模型構造函數
var User = mongoose.model('User', userSchema); //第一個參數是字符串,第二個參數是一個架構
// 4.當我們有了模型構造韓素華之后,就可以使用這個構造函數對users集合中的數據進行(增刪改查)

增加數據

var admin = new User({
    username: 'admin',
    passworld: '123456',
    email: 'admin@admin.com'
});
admin.save(function(err, ret) {//里面的兩個方法用來查看是否將數據存進去
    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
        })
    })

查詢數據

? 查詢所有數據:

// ***********************
// #region 查詢數據所有數據
// ***********************
User.find(function(err, ret) {
    if (err) {
        console.log('失敗');
    } else {
        console.log(ret);
    }
})

按照條件查詢數據(查詢出來的是數組里面存放的是對象):

User.find({
    username: '張三'
    //年齡大于18去API查
}, function(err, ret) {
    if (err) {
        console.log('失敗');
    } else {
        console.log(ret);
    }
})

按照條件查詢數據(查詢出來的是數據直接存放在對象中()):

User.findOne({ //如果第一個沒有參數,那么查詢的就是第一個數據
    username: '張三', //多個數據直接在后面跟就好了
    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)//表示輸出第一行數據
user.getIndexes();

刪除數據

根據條件刪除所有

User.remove({
    username: '張三'
}, function(err, ret) {
    if (err) {
        console.log('失敗');
    }
    console.log('成功');
    console.log(ret);//所有的張三都刪除了

})

根據條件刪除一個

Model.findOneAndRemove(conditions,[options],[callback])

根據id刪除一個

Model.findByIdAndRemove(id,[options],[callback])

更新數據

根據條件更新所有:

Model.update(conditions,doc,[options],[callback])

根據指定條件更新一個:

Model.findOneAndUpdate([conditions],[update],[options],[callback])

根據id更新一個

// 第一個參數是他的MongoDB的id,第二個參數是你所想要修改的值,第三個是回調函數是否成功的
User.findByIdAndUpdate('5e0749619ca65b30b05a69ca', {
    passworld: '123'
}, function(err, ret) {
    if (err) {
        console.log('失敗');
    } else {
        console.log('成功');

    }
})

Mongodb 對內嵌數組的增刪改查操作

先做一個初始化堆缘,設置一個User類,其初始數據如下:

{ arr: [ 1, 2 ],
  _id: 5ac5ee12a79131259413c40f,
  name: 'scy',
  __v: 0 }

每次以初始數據為基送膳,進行操作员魏。

1、向內嵌數組添加數據

使用操作符 $push叠聋,向數組末尾添加數據 撕阎,可重復

//第一個參數是匹配條件 第二個參數是具體操作
    User.update({name:"scy"},{$push:{"arr":3}});//向user里面的arr末尾追加元素3

結果如下:

{ arr: [ 1, 2, 3 ],
  _id: 5ac5f0d3db343b1888a8969d, name: 'scy',__v: 0 }

一次添加多個數據

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) { //里面的兩個方法用來查看是否將數據存進去
                if (err) {
                    console.log('失敗');
                } else {
                    console.log(req.query);
                    console.log(ret._id);
//注意就是這里將上一個''引號可以轉換
                    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、刪除內嵌數組指定數據

注意添加的時候加一個''引號這樣可以將id轉為字符串

使用操作符 $pull

//刪除arr所有數據為2的元素
  User.update({name:"scy"},{$pull:{"arr":2}});

執(zhí)行結果:

{ arr: [ 1 ], _id: 5ac5f39fdad94e23e8de9aee, name: 'scy', __v: 0 }

如果數組元素是對象,可以根據對象屬性操作:

{
  name:"scy",
  mArray:[{age:13,weight:50},{age:13,weight:30}]
}
User.update({name:"scy"},{$pull:{"mArray":{"weight":30}}});//刪除所有weight屬性值為30的對象

MongoDB,從數組中刪除對象

{
   _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碌补、修改內嵌數組指定數據

  1. 數據截圖:

    [圖片上傳失敗...(image-614047-1601889185798)]

  1. 我想更新arr_1數組中虏束,a = 1 的對象,更新為 {a:11,b:12} 運行更新代碼厦章,如下:

    [
    復制代碼

    ](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',
                        }]
                    }
    

    [
    復制代碼

    ](javascript:void(0);)

我暫時還沒找到能批量修改數組元素的方法

1
3镇匀、修改內嵌數組指定數據
我暫時還沒找到能批量修改數組元素的方法

//將數組里面的第一個元素1修改為3
User.update({"arr":{$all:[1]}},{$set:{"arr.$":2}});
//也可以根據下標
User.update({$set:{"arr.1":22}});//將arr下標為1的元素修改為22

如果數組的元素是對象,如下:

1
2
如果數組的元素是對象袜啃,如下:

{
  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是下標 
User.update({$set:{"mArray.1.age":22}});//將arr第二個元素對象的age改為22

批量修改內嵌數組對象

//computer1數據表
//data.$[].network數組下面的數據
computer1.update({'roomNumber': req.query.w}, {$set: {'data.$[].network': 10}}, {multi: true},function(a,s){
            console.log(a);
            console.log(s);
            
        })

4汗侵、查詢內嵌數組并返回指定的數據

使用$size 返回指定數組長度的數據

//$size限制比較大 下面表示查詢數組長度為2的數據
User.find({arr:{$size:2}})

$slice,這個操作符還是比較強大的適合查詢數組中的數據

//匹配到的user 將其數組截取第一個返回 如[1,1,2]返回[1]
User.findOne({name:"scy"},{arr:{$slice:1}});
//將匹配到的user的數組 截取返回后面兩個元素  如[1,1,2]返回[1,2]
User.findOne({name:"scy"},{arr:{$slice:-2}});
//從數組的下表為1的元素開始 返回兩個 如[1,3,2]返回[3,2]
User.findOne({name:"scy"},{arr:{$slice:[1,2]}});

$elemMatch查詢的是某一個數據

用法如下:

User.findOne({name:"scy"},{arr:{$elemMatch:{key:val}});

總的代碼案例如下:

在當前的目錄下的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

數 據 \color{red}{數據}數據

數據使用菜鳥教程的數據啦????

/* 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)計結果
$match 過濾數據囊骤,只輸出符合結果的文檔
$project 修改輸入文檔的結構(例如重命名晃择,增加、刪除字段也物,創(chuàng)建結算結果等)
$sort 將結果進行排序后輸出
$limit 限制管道輸出的結果個數
$skip 跳過制定數量的結果宫屠,并且返回剩下的結果
$unwind 將數組類型的字段進行拆分

表 達 式 操 作 符 \color{red}{表達式操作符}表達式操作符

操作符 含義 實例
$sum 計算總和,{$sum: 1}表示返回總和×1的值(即總和的數量),使用{$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 獲取集合中所有文檔對應值得最小值 db.collection.aggregate([{$group : {_id : "$by_user", content_sum : {$min : "$likes"}}}])
$max 獲取集合中所有文檔對應值得最大值 db.collection.aggregate([{$group : {_id : "$by_user", content_sum : {$max : "$likes"}}}])
$push 在結果文檔中插入值到一個數組中 db.collection.aggregate([{$group : {_id : "$by_user", url : {$push : "$url"}}}])
$addToSet 在結果文檔中插入值到一個數組中滑蚯,但不創(chuàng)建副本 db.collection.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}])
$first 根據資源文檔的排序獲取第一個文檔數據 db.collection.aggregate([{$group : {_id : "$by_user", url : {$first : "$url"}}}])
$last 根據資源文檔的排序獲取最后一個文檔數據 db.collection.aggregate([{$group : {_id : "$by_user", url : {$last : "$url"}}}])

具 體 例 子 \color{skyblue}{具體例子}具體例子

  • $group

    • 簡單闡述

      //將document分組浪蹂,用作統(tǒng)計結果
      db.collection.aggregate([       // aggregate方法接收的是一個數組
          {
              $group: {
                  // _id字段表示要基于哪個字段來進行分組(即制定字段值相同的為一組)
                  // $by_user表示要基于$by_user字段來進行分組
                  _id: '$by_user', 
                  // content_sum字段的值$sum: 1表示的是獲取滿足by_user字段相同的這一組的數量乘以后面給定的值(本例為1,那么就是同組的數量)告材。
                  content_sum: {$sum: 1}
              }
          }
      ])
      123456789101112
      
    • 具體案例

      通過以上集合計算每個作者所寫的文章數(通過字段by_user 字段對數據進行分組坤次,并計算by_user字段相同值的總和),使用aggregate()計算結果如下:

      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之間的數據:

    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之間的數據只有1條斥赋,現在我們只知道這條數據的_id缰猴,如果想知道這條數據的具體信息時應該如何操作呢?上面的表格中提到$project修改輸入文檔的結構(例如重命名,增加疤剑、刪除字段滑绒,創(chuàng)建結算結果等)闷堡,所以一起來看看吧??????

  • $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的順序,換位置后數據為空
        {
          $project: {
            _id: 0, //_id不顯示
            by_user: 1 //by_user顯示
          }
        },
        {
          $group: {
            _id: null,
            gameName: {
              $push: '$by_user'
            }
          }
        }
      ])
      res.json({
        data
      })
    })
    12345678910111213141516171819202122232425262728
    
    在這里插入圖片描述
  • $sort

    • 根據likes進行降序排序

      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
      
      在這里插入圖片描述
    • 根據likes進行升序排序

      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
      
      在這里插入圖片描述
  • limit andskip

    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中的數組類型的字段進行拆分,每條包含數組中的一個值纵势。

    比如拆分likes:10這條數據踱阿,先來看看整體數據信息吧:

    {
        "_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數組中有3條數據,所以拆分后會顯示3條數據钦铁,看看具體實現吧:

    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
    
    在這里插入圖片描述
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末软舌,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子育瓜,更是在濱河造成了極大的恐慌葫隙,老刑警劉巖栽烂,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件躏仇,死亡現場離奇詭異,居然都是意外死亡腺办,警方通過查閱死者的電腦和手機焰手,發(fā)現死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怀喉,“玉大人书妻,你說我怎么就攤上這事」#” “怎么了躲履?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長聊闯。 經常有香客問我工猜,道長,這世上最難降的妖魔是什么菱蔬? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任篷帅,我火速辦了婚禮,結果婚禮上拴泌,老公的妹妹穿的比我還像新娘魏身。我一直安慰自己,他們只是感情好蚪腐,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布箭昵。 她就那樣靜靜地躺著,像睡著了一般回季。 火紅的嫁衣襯著肌膚如雪家制。 梳的紋絲不亂的頭發(fā)上掉房,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天,我揣著相機與錄音慰丛,去河邊找鬼卓囚。 笑死,一個胖子當著我的面吹牛诅病,可吹牛的內容都是我干的哪亿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼贤笆,長吁一口氣:“原來是場噩夢啊……” “哼蝇棉!你這毒婦竟也來了?” 一聲冷哼從身側響起芥永,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤篡殷,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后埋涧,有當地人在樹林里發(fā)現了一具尸體板辽,經...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年棘催,在試婚紗的時候發(fā)現自己被綠了劲弦。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡醇坝,死狀恐怖邑跪,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情呼猪,我是刑警寧澤画畅,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站宋距,受9級特大地震影響轴踱,放射性物質發(fā)生泄漏。R本人自食惡果不足惜乡革,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一寇僧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧沸版,春花似錦嘁傀、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春笑撞,著一層夾襖步出監(jiān)牢的瞬間岛啸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工茴肥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留坚踩,地道東北人。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓瓤狐,卻偏偏與公主長得像瞬铸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子础锐,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354