node.js連接mongodb數(shù)據(jù)庫

第一種

安裝

在命令行中下載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
  })
})
img

$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ù)

  1. 數(shù)據(jù)截圖:

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

  1. 我想更新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安裝

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包再一次做了封裝

https://mongoosejs.com/

第三方包連接數(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ù)

  1. 數(shù)據(jù)截圖:

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

  1. 我想更新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
      
      在這里插入圖片描述
  • 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中的數(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
    
    在這里插入圖片描述
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容