MongoDB 強大查詢操做之aggregate

一、聚合簡介

在MongoDB中,使用聚合框架能夠對集合中的文檔進行變換和組合,完成一些複雜的查詢操做。聚合框架經過多個階段來建立一個管道(pipeline),用於對一連串的文檔進行處理。這些構件包括但不限於:前端

聚合操做就是經過aggregate()函數來完成一系列的聚合查詢,主要用於處理如:統計,平均值,求和等,並返回計算後的結果。python

語法:linux

db.collection.aggregate{
  [
    {$group:{_id:"$分組鍵名"}, "$分組鍵名", 別名:{聚合運算: "$運算列"} },
    {條件篩選:{鍵名:{運算條件:運算值}}}
  ]
}

管道操做符golang

操做符 描述
$match 過濾數據,只輸出符合結果的文檔(也能夠對分組的數組作過濾)
$project 投射,選擇想要的字段或對字段進行重命名
$group 將集合中的文檔分組,可用於統計結果
$unwind 拆分
$sort 排序
$limit 限制查詢條數
$skip 跳過一些條數
$lookup 多表關聯查詢

表達式操做符sql

操做符 描述
$sum 計算總和,{$sum: 1}表示返回總和×1的值(即總和的數量),使用{$sum: '$制定字段'}也能直接獲取制定字段的值的總和
$avg 求平均值
$min 求最小值
$max 求最大值
$push 將結果文檔中插入值到一個數組中
$first 根據文檔的排序獲取第一個文檔數據
$skip 跳過一些條數
$last 同理,獲取最後一個數據

二、簡單練習

造一個測試文檔,後面圍繞這個文檔作聚合操做mongodb

db.orders.insertMany([
{
  cust_id: "a1300123",
  ord_date: ISODate("2020-06-22T17:04:11.102Z"),
  status: 'success',
  price: 85,
  items: [ { sku: "beef", qty: 30, amount: 1 },
           { sku: "mutton", qty: 25, amount: 1 },
           { sku: "beer", qty: 10, amount: 3 }
         ]
},
{
  cust_id: "a1300123",
  ord_date: ISODate("2020-06-22T17:04:11.102Z"),
  status: 'success',
  price: 100,
  items: [ { sku: "beef", qty: 30, amount: 1 },
           { sku: "mutton", qty: 25, amount: 2 },
           { sku: "beer", qty: 10, amount: 3 }
         ]
},
{
  cust_id: "a1300124",
  ord_date: ISODate("2020-06-22T17:04:11.102Z"),
  status: 'success',
  price: 85,
  items: [ { sku: "beef", qty: 30, amount: 1 },
           { sku: "mutton", qty: 25, amount: 1 },
           { sku: "beer", qty: 10, amount: 1 }
         ]
},
{
  cust_id: "a1300124",
  ord_date: ISODate("2020-06-22T17:04:11.102Z"),
  status: 'success',
  price: 105,
  items: [ { sku: "beef", qty: 30, amount: 2 },
           { sku: "mutton", qty: 25, amount: 1 },
           { sku: "beer", qty: 10, amount: 1 }
         ]
},
])

1.統計orders集合全部記錄數據庫

db.orders.aggregate( [
   {
     $group: {
        _id: null,
        count: { $sum: 1 }
     }
   }
] )

// 結果
{ "_id": null, "count": 4 }

Note:這裏的$sum:1 表示的就是統計全部記錄數組

2.計算orders集合全部文檔price的總和架構

db.orders.aggregate([
  {
    $group: {
      _id: null,
      total_price: { $sum: "$price"}
    }
  }
])

// 結果
{ "_id": null, "total_price": 375 }

3.對於每個惟一的cust_id,計算price總和框架

db.orders.aggregate([
  {
    $group: {
      _id: '$cust_id',
      total_price: { $sum: "$price"}
    }
  }
])

// 結果
{ "_id": "a1300123", "total_price": 185 }
{ "_id": "a1300124", "total_price": 190 }

4.對每個惟一對cust_id和ord_date分組,計算price總和,不包括日期的時間部分

db.orders.aggregate( [
   {
     $group: {
        _id: {
           cust_id: "$cust_id",
           ord_date: {
               month: { $month: "$ord_date" },
               day: { $dayOfMonth: "$ord_date" },
               year: { $year: "$ord_date"}
           }
        },
        total: { $sum: "$price" }
     }
   }
] )

// 結果
{ "_id": { "cust_id": "a1300124", "ord_date": { "month": 6, "day": 22, "year": 2020 } }, "total": 190 }
{ "_id": { "cust_id": "a1300123", "ord_date": { "month": 6, "day": 22, "year": 2020 } }, "total": 185 }

5.對於有多個記錄的cust_id,返回cust_id和對應的數量

db.orders.aggregate([
  {
    $group: {
      _id: "$cust_id",
      count: {$sum : 1}
    }
  }
])

// 結果
{ "_id": "a1300123", "count": 2 }
{ "_id": "a1300124", "count": 2 }

6.對每一個惟一的cust_id和ord_date分組,計算價格總和,並只返回price總和大於等於190的記錄,且排除日期的時間部分

db.orders.aggregate([
  {
    $group: {
      _id: {
        cust_id: "$cust_id",
        ord_date:{
            month: { $month: "$ord_date" },
            day: { $dayOfMonth: "$ord_date" },
            year: { $year: "$ord_date"}
        }
      },
      total: {$sum: "$price"}
    }
  },
  { $match: {total: {$gte: 190 }}}
])

// 結果
{ "_id": { "cust_id": "a1300124", "ord_date": { "month": 6, "day": 22, "year": 2020 } }, "total": 190 }

7.對每一個惟一的cust_id且status=success,計算price總和

db.orders.aggregate([
  {$match: { status: 'success'} },
  {
    $group:{
      _id: '$cust_id',
      total: { $sum: '$price'}
    }
  }
])

// 結果
{ "_id": "a1300124", "total": 190 }
{ "_id": "a1300123", "total": 185 }

8.統計每一個orders文檔裏菜單的價格 * 購買數量

db.orders.aggregate( [
  { $unwind: "$items" },
  {$project: {cust_id: '$cust_id',total: { $multiply: ["$items.qty", "$items.amount"]}}},
])
    
// 結果
{ "_id": ObjectId("5ef0230a3e2cd6e9f70b94a1"), "total": 30 }
{ "_id": ObjectId("5ef0230a3e2cd6e9f70b94a1"), "total": 25 }
{ "_id": ObjectId("5ef0230a3e2cd6e9f70b94a1"), "total": 30 }
{ "_id": ObjectId("5ef0230a3e2cd6e9f70b94a2"), "total": 30 }
{ "_id": ObjectId("5ef0230a3e2cd6e9f70b94a2"), "total": 50 }
{ "_id": ObjectId("5ef0230a3e2cd6e9f70b94a2"), "total": 30 }
{ "_id": ObjectId("5ef0230a3e2cd6e9f70b94a3"), "total": 30 }
{ "_id": ObjectId("5ef0230a3e2cd6e9f70b94a3"), "total": 25 }
{ "_id": ObjectId("5ef0230a3e2cd6e9f70b94a3"), "total": 10 }
{ "_id": ObjectId("5ef0230a3e2cd6e9f70b94a4"), "total": 60 }
{ "_id": ObjectId("5ef0230a3e2cd6e9f70b94a4"), "total": 25 }
{ "_id": ObjectId("5ef0230a3e2cd6e9f70b94a4"), "total": 10 }

三、聚合操做

模擬數據

db.dev.insertMany([
  {title: 'Linux運維班', description: '某小廠工程師主講', url: 'www.qylinux.com', tags: ['Linux基礎', 'linux'] ,price: 12000},
  {title: 'Linux架構師', description: '某大廠資深工程師主講', url: 'www.qylinux.com', tags: ['Linux架構', 'linux'] ,price: 18000},
  {title: 'Python自動化運維', description: '鵝廠高級自動化運維經理主講', url: 'www.qypython.com', tags: ['Python', '運維', '自動化運維'] ,price: 21500},
  {title: 'Python全棧', description: 'AWS開發經理主講', url: 'www.qypython.com', tags: ['Python', 'AWS', '前端'] ,price: 25600},
  {title: 'Golang全棧', description: 'Google資深工程師主講', url: 'www.qygolang.com', tags: ['Golang', '21世紀C語言'] ,price: 25600},
  {title: 'AWS架構師', description: 'AWS東南亞首席CTO主講', url: 'www.qyaws.com', tags: ['AWS', '雲計算', '虛擬化'] ,price: 18000},
])

3.1 求和-$sum

1.查詢dev集合中一共有多少個文檔

// sql
select count(*) AS count FORM dev
             
// mongodb
db.dev.aggregate([
		{
      $group:{
       _id: null, 
       count: { $sum: 1}
			}
		}
])

返回結果:

{ "_id": null, "count": 6 }

參數解釋:

$group:分組,表明聚合的分組條件。
_id:分組的字段,不能缺乏,必需要有,若是根據某字段的值分組,則定義爲_id: '$字段名',因此此案例中的null表明一個固定的字面值'null'。
count:返回結果字段名,能夠自定義,相似SQL中的字段別名。
$sum:求和表達式,至關於SQL中的sum()。
1:累加值

2.查詢dev集合中全部price鍵中鍵值的總和

// $price表示文檔中的price字段的值
db.dev.aggregate([
  {
    $group: {
      _id: null,
      totalPrice: { $sum: '$price' }
    }
  }
])

返回結果:

{ "_id": null, "totalPrice": 120700 }

3.對每一個title進行分組並計算每組的price的總和

// $price表示文檔中的price字段的值
db.dev.aggregate([
  {
    $group: {
      _id: '$title',
      totalPrice: { $sum: '$price' }
    }
  }
])

返回結果:

{ "_id": "Linux運維班", "totalPrice": 12000 }
{ "_id": "Python全棧", "totalPrice": 25600 }
{ "_id": "Linux架構師", "totalPrice": 18000 }
{ "_id": "Golang全棧", "totalPrice": 25600 }
{ "_id": "Python自動化運維", "totalPrice": 21500 }
{ "_id": "AWS架構師", "totalPrice": 18000 }

3.2 過濾-$match

$match 匹配條件,至關於SQL中的where子句,表明聚合以前進行條件篩選

1.查詢dev集合中有多少文檔的price大於20000

db.dev.aggregate([
  {
    $match: { 
      price: { $gt: 20000}
    }
  },
  {
    $group: {
      _id: null,
      count: { $sum: 1 }
    }
  }
])

返回結果:

{ "_id": null, "count": 3 }

2.查詢dev集合,根據title分組計算出每組的price總和,並過濾掉總和小於等於20000的文檔

db.dev.aggregate([
  {
    $group: {
      _id: '$title',
      totalPrice: { $sum: '$price' }
    }
  },
  {
    $match: {
      totalPrice: { $lte: 20000 }
    }
  }
])

返回結果:

{ "_id": "Linux運維班", "totalPrice": 12000 }
{ "_id": "Linux架構師", "totalPrice": 18000 }
{ "_id": "AWS架構師", "totalPrice": 18000 }

3.3 最大值-$max

查詢dev集合中price最大的文檔,

$max: '$price' :計算price鍵的最大值

db.dev.aggregate([
  {
    $group: {
      _id: null,
      maxPirce: { $max: '$price' }
    }
  }
])

返回結果:

{ "_id": null, "maxPirce": 25600 }

3.4 最小值-$min

查詢dev集合中price最小的文檔,

$min: '$price' :計算price鍵的最小值

db.dev.aggregate([
  {
    $group: {
      _id: null,
      minPirce: { $min: '$price' }
    }
  }
])

返回結果:

{ "_id": null, "minPirce": 12000 }

3.5 平均值-$avg

查詢dev集合中price的平均值,

$avg: '$price' 計算price鍵的平均值

db.dev.aggregate([
  {
    $group: {
      _id: null,
      avgPrice: { $avg: '$price' }
    }
  }
])

返回結果:

{ "_id": null, "avgPrice": 20116.666666666668 }

3.6 統計結果返回數組-$push

查詢dev集合,按照price分組並返回它們的title,若是price相同則使用數組返回它們的title。

$push: '$title':若是price相同則使用數組返回它們的title

db.dev.aggregate([
  {
    $group: {
      _id: '$price',
      title: { $push: '$title' }
    }
  }
])

返回結果:

{ "_id": 25600, "title": [ "Python全棧", "Golang全棧" ] }
{ "_id": 12000, "title": [ "Linux運維班" ] }
{ "_id": 18000, "title": [ "Linux架構師", "AWS架構師" ] }
{ "_id": 21500, "title": [ "Python自動化運維" ] }

3.7 數組字段拆分-$unwind

查詢dev集合,將數組中的內容拆分顯示

$unwind: '$tags':對數組中的元素進行拆分顯示

db.dev.aggregate([
  { $unwind: '$tags' }
])

返回結果:

....... 省略文檔 ........
Fetched 15 record(s) in 3ms

3.8 管道操做

管道在Unix和Linux中通常用於將當前命令的輸出結果做爲下一個命令的參數。

MongoDB的聚合管道將MongoDB文檔在一個管道處理完畢後將結果傳遞給下一個管道處理,管道操做是能夠重複的。

管道操做符是按照書寫的順序依次執行的,每一個操做符都會接受這一串的文檔,而後對文檔作相應的轉換操做,最後將轉換後的文檔做爲結果傳遞給下一個操做符(對於最後一個管道操做符,是將結果返回給客戶端),稱爲流式工做方式

管道操做符:$match、$group、$sort、$skip、$unwind .......

Note:管道操做符只能處理當前聚合的文檔,而不能處理管道之外的其它文檔。

3.8.一、聚合投影約束-$project

$project操做符:咱們可使用$project操做符作聚合投影操做

1.查詢dev集合,將數組中的內容拆分顯示,並只顯示title鍵與tags鍵的值

db.dev.aggregate([
  { $unwind: '$tags' },
  { 
    $project: {
      _id: 0,
      title: '$title',
      tags: '$tags'
   }
  }
])

返回結果:

{ "title": "Linux運維班", "tags": "Linux基礎" }
{ "title": "Linux運維班", "tags": "linux" }
{ "title": "Linux架構師", "tags": "Linux架構" }
{ "title": "Linux架構師", "tags": "linux" }
{ "title": "Python自動化運維", "tags": "Python" }
{ "title": "Python自動化運維", "tags": "運維" }
{ "title": "Python自動化運維", "tags": "自動化運維" }
{ "title": "Python全棧", "tags": "Python" }
{ "title": "Python全棧", "tags": "AWS" }
{ "title": "Python全棧", "tags": "前端" }
{ "title": "Golang全棧", "tags": "Golang" }
{ "title": "Golang全棧", "tags": "21世紀C語言" }
{ "title": "AWS架構師", "tags": "AWS" }
{ "title": "AWS架構師", "tags": "雲計算" }
{ "title": "AWS架構師", "tags": "虛擬化" }

2.查詢dev集合,將數組中的內容拆分顯示,要求值顯示title鍵與tags鍵的值並將title鍵改成Title

db.dev.aggregate([
  { $unwind: '$tags' },
  { 
    $project: {
      _id: 0,
      Title: '$title',
      tags: '$tags'
   }
  }
])

返回結果:

{ "Title": "Linux運維班", "tags": "Linux基礎" }
{ "Title": "Linux運維班", "tags": "linux" }
{ "Title": "Linux架構師", "tags": "Linux架構" }
{ "Title": "Linux架構師", "tags": "linux" }
{ "Title": "Python自動化運維", "tags": "Python" }
{ "Title": "Python自動化運維", "tags": "運維" }
{ "Title": "Python自動化運維", "tags": "自動化運維" }
{ "Title": "Python全棧", "tags": "Python" }
{ "Title": "Python全棧", "tags": "AWS" }
{ "Title": "Python全棧", "tags": "前端" }
{ "Title": "Golang全棧", "tags": "Golang" }
{ "Title": "Golang全棧", "tags": "21世紀C語言" }
{ "Title": "AWS架構師", "tags": "AWS" }
{ "Title": "AWS架構師", "tags": "雲計算" }
{ "Title": "AWS架構師", "tags": "虛擬化" }

3.8.二、字符串處理-$project

$project中能夠經過MongoDB的字符串操做符對投影的內容作字符串處理

1.查詢dev集合,將數組中的內容拆分顯示,將title中的值轉換爲小寫並命名爲New_Title,將tags的值轉換爲大寫並命名爲New_Tags。

New_Title:{ $toLower: '$title'}:將title中的值轉換爲小寫

New_Tags:{ $toUpper: '$tags'}: 將tags中的值轉換爲大寫

db.dev.aggregate([
  { $unwind: '$tags' },
  { 
    $project: {
      _id: 0,
      New_Title: { $toLower: '$title'},
      New_Tags: { $toUpper: '$tags'}
    }
  }
])

返回結果:

{ "New_Title": "linux運維班", "New_Tags": "LINUX基礎" }
{ "New_Title": "linux運維班", "New_Tags": "LINUX" }
{ "New_Title": "linux架構師", "New_Tags": "LINUX架構" }
{ "New_Title": "linux架構師", "New_Tags": "LINUX" }
{ "New_Title": "python自動化運維", "New_Tags": "PYTHON" }
{ "New_Title": "python自動化運維", "New_Tags": "運維" }
{ "New_Title": "python自動化運維", "New_Tags": "自動化運維" }
{ "New_Title": "python全棧", "New_Tags": "PYTHON" }
{ "New_Title": "python全棧", "New_Tags": "AWS" }
{ "New_Title": "python全棧", "New_Tags": "前端" }
{ "New_Title": "golang全棧", "New_Tags": "GOLANG" }
{ "New_Title": "golang全棧", "New_Tags": "21世紀C語言" }
{ "New_Title": "aws架構師", "New_Tags": "AWS" }
{ "New_Title": "aws架構師", "New_Tags": "雲計算" }
{ "New_Title": "aws架構師", "New_Tags": "虛擬化" }

2.查詢dev集合,將數組中的內容拆分顯示,將title字段和tags字段的值拼接爲一個完整字符串並在Title_Tags字段中顯示。

db.dev.aggregate([
  { $unwind: '$tags' },
  { 
    $project: {
      _id: 0,
      Title_Tags: { $concat: ['$title','-','$tags']},
   }
  }
])

返回結果:

{ "Title_Tags": "Linux運維班-Linux基礎" }
{ "Title_Tags": "Linux運維班-linux" }
{ "Title_Tags": "Linux架構師-Linux架構" }
{ "Title_Tags": "Linux架構師-linux" }
{ "Title_Tags": "Python自動化運維-Python" }
{ "Title_Tags": "Python自動化運維-運維" }
{ "Title_Tags": "Python自動化運維-自動化運維" }
{ "Title_Tags": "Python全棧-Python" }
{ "Title_Tags": "Python全棧-AWS" }
{ "Title_Tags": "Python全棧-前端" }
{ "Title_Tags": "Golang全棧-Golang" }
{ "Title_Tags": "Golang全棧-21世紀C語言" }
{ "Title_Tags": "AWS架構師-AWS" }
{ "Title_Tags": "AWS架構師-雲計算" }
{ "Title_Tags": "AWS架構師-虛擬化" }

Note:$concat的數組中給定須要拼接的值。

3.查詢dev集合,將數組中的內容拆分顯示,只顯示title字段的前3個字符,並命名爲Title_Prefix

Title_Prefix: { $substr: ['$title',0,3]}:將title的值從0開始截取3位,並命名爲Title_Prefix

db.dev.aggregate([
  { $unwind: '$tags' },
  { 
    $project: {
      _id: 0,
      Title_Prefix: { $substr: ['$title',0,3]},
   }
  }
])

返回結果:

{ "Title_Prefix": "Lin" }
{ "Title_Prefix": "Lin" }
{ "Title_Prefix": "Lin" }
{ "Title_Prefix": "Lin" }
{ "Title_Prefix": "Pyt" }
{ "Title_Prefix": "Pyt" }
{ "Title_Prefix": "Pyt" }
{ "Title_Prefix": "Pyt" }
{ "Title_Prefix": "Pyt" }
{ "Title_Prefix": "Pyt" }
{ "Title_Prefix": "Gol" }
{ "Title_Prefix": "Gol" }
{ "Title_Prefix": "AWS" }
{ "Title_Prefix": "AWS" }
{ "Title_Prefix": "AWS" }

對於$substr只能匹配ASCII的數據,對於中文要使用$substrCP

db.dev.aggregate([
  { $unwind: '$tags' },
  { 
    $project: {
      _id: 0,
      Title_Prefix: { $substrCP: ['$title',0,6]},
    }
  }
])

返回結果:

{ "Title_Prefix": "Linux運" }
{ "Title_Prefix": "Linux運" }
{ "Title_Prefix": "Linux架" }
{ "Title_Prefix": "Linux架" }
{ "Title_Prefix": "Python" }
{ "Title_Prefix": "Python" }
{ "Title_Prefix": "Python" }
{ "Title_Prefix": "Python" }
{ "Title_Prefix": "Python" }
{ "Title_Prefix": "Python" }
{ "Title_Prefix": "Golang" }
{ "Title_Prefix": "Golang" }
{ "Title_Prefix": "AWS架構師" }
{ "Title_Prefix": "AWS架構師" }
{ "Title_Prefix": "AWS架構師" }

3.8.三、算數運算-$project

$project中咱們能夠經過MongoDB的算數操做符對投影的內容進行運算處理

1.查詢dev集合中數據,顯示title和price字段,爲price字段的數據作加1操做,顯示字段名爲New_Price

db.dev.aggregate([
  { 
    $project: {
      _id: 0,
      title: 1,
      New_Price: { $add: ['$price',1]}
    }
  }
])

返回結果:

{ "title": "Linux運維班", "New_Price": 12001 }
{ "title": "Linux架構師", "New_Price": 18001 }
{ "title": "Python自動化運維", "New_Price": 21501 }
{ "title": "Python全棧", "New_Price": 25601 }
{ "title": "Golang全棧", "New_Price": 25601 }
{ "title": "AWS架構師", "New_Price": 18001 }

2.查詢dev集合中數據,顯示title和price字段,爲price字段的數據作減1操做,顯示字段名爲New_Price

db.dev.aggregate([
  { 
    $project: {
      _id: 0,
      title: 1,
      New_Price: { $subtract: ['$price',1]}
    }
  }
])

返回結果:

{ "title": "Linux運維班", "New_Price": 11999 }
{ "title": "Linux架構師", "New_Price": 17999 }
{ "title": "Python自動化運維", "New_Price": 21499 }
{ "title": "Python全棧", "New_Price": 25599 }
{ "title": "Golang全棧", "New_Price": 25599 }
{ "title": "AWS架構師", "New_Price": 17999 }

3.查詢dev集合中數據,顯示title和price字段,爲price字段的數據作乘2操做,顯示字段名爲New_Price

db.dev.aggregate([
  { 
    $project: {
      _id: 0,
      title: 1,
      New_Price: { $multiply: ['$price',2]}
    }
  }
])

返回結果:

{ "title": "Linux運維班", "New_Price": 24000 }
{ "title": "Linux架構師", "New_Price": 36000 }
{ "title": "Python自動化運維", "New_Price": 43000 }
{ "title": "Python全棧", "New_Price": 51200 }
{ "title": "Golang全棧", "New_Price": 51200 }
{ "title": "AWS架構師", "New_Price": 36000 }

4.查詢dev集合中數據,顯示title和price字段,爲price字段的數據作除2操做,顯示字段名爲New_Price

db.dev.aggregate([
  { 
    $project: {
      _id: 0,
      title: 1,
      New_Price: { $divide: ['$price',2]}
    }
  }
])

返回結果:

{ "title": "Linux運維班", "New_Price": 6000 }
{ "title": "Linux架構師", "New_Price": 9000 }
{ "title": "Python自動化運維", "New_Price": 10750 }
{ "title": "Python全棧", "New_Price": 12800 }
{ "title": "Golang全棧", "New_Price": 12800 }
{ "title": "AWS架構師", "New_Price": 9000 }

5.查詢dev集合中數據,顯示title和price字段,爲price字段的數據作模2操做,顯示字段名爲New_Price

db.dev.aggregate([
  { 
    $project: {
      _id: 0,
      title: 1,
      New_Price: { $mod: ['$price',2]}
    }
  }
])

返回結果:

{ "title": "Linux運維班", "New_Price": 0 }
{ "title": "Linux架構師", "New_Price": 0 }
{ "title": "Python自動化運維", "New_Price": 0 }
{ "title": "Python全棧", "New_Price": 0 }
{ "title": "Golang全棧", "New_Price": 0 }
{ "title": "AWS架構師", "New_Price": 0 }

3.9 多表關聯-lookup

MongoDB很難像關係型數據庫同樣擅長多表關聯,MongoDB提供了$lookup來實現多表關聯

模擬數據:好比咱們有一個product表和一個orders表,咱們orders集合中的文檔經過pid關聯到對應的product文檔的_id字段

db.product.insert({_id: 1, name: '商品1', price: 15})
db.product.insert({_id: 2, name: '商品2', price: 23})


db.orders.insert({_id: 1, pid: 1, name: '訂單1'})
db.orders.insert({_id: 2, pid: 2, name: '訂單2'})
db.orders.insert({_id: 3, pid: 2, name: '訂單3'})
db.orders.insert({_id: 4, pid: 1, name: '訂單4'})


db.product.find()
db.orders.find()

1.在orders表中,找到price > 20的訂單

1)咱們orders表中是沒有field的,第一步應該執行:

db.product.aggregate([
    {
      $lookup:
        {
          from: "orders",
          localField: "_id",
          foreignField: "pid",
          as: "inventory_docs"
        }
   }
])

返回結果:

{ "_id": 1, "name": "商品1", "price": 15, "inventory_docs": [   {   "_id": 1,   "pid": 1,   "name": "訂單1" },   {   "_id": 4,   "pid": 1,   "name": "訂單4" } ] }
{ "_id": 2, "name": "商品2", "price": 23, "inventory_docs": [   {   "_id": 2,   "pid": 2,   "name": "訂單2" },   {   "_id": 3,   "pid": 2,   "name": "訂單3" } ] }

簡單介紹$lookup中的參數:

form:須要關聯的表(orders)
localField:orders被product的關聯的鍵
foreignField:orders和product有關聯的鍵
as:對應的外鍵集合數據(可能存在一對多的狀況)

2)$match篩選

db.product.aggregate([
    {
      $lookup:
        {
          from: "orders",
          localField: "_id",
          foreignField: "pid",
          as: "inventory_docs"
        }
   },
  { $match: {price: {$gt: 20 } }}
])

返回結果:

{ "_id": 2, "name": "商品2", "price": 23, "inventory_docs": [   {   "_id": 2,   "pid": 2,   "name": "訂單2" },   {   "_id": 3,   "pid": 2,   "name": "訂單3" } ] }

3)$project挑選字段

咱們只須要inventory_docs字段便可

db.product.aggregate([
    {
      $lookup:
        {
          from: "orders",
          localField: "_id",
          foreignField: "pid",
          as: "inventory_docs"
        }
   },
  { $match: {price: {$gt: 20 } }},
  { $project: {"inventory_docs": 1, "_id": 0} }
])

返回結果:

{ "inventory_docs": [   {   "_id": 2,   "pid": 2,   "name": "訂單2" },   {   "_id": 3,   "pid": 2,   "name": "訂單3" } ] }
相關文章
相關標籤/搜索