上篇最後說到管道操做符,本篇文章將詳細說一下管道操做符。mongodb
mongoDB有4類操做符用於文檔的操做,例如find查詢裏面會用到的$gte,$in等。操做符以$開頭,分爲查詢操做符,更新操做符,管道操做符,查詢修飾符4大類。其中管道操做符是用於聚合管道中的操做符。express
管道操做符能夠分爲三類:json
此處中文勉強翻譯,以英文爲準,歡迎大神給意見,謝謝。segmentfault
參考MongoDB官網:https://docs.mongodb.com/manual/reference/operator/aggregation/#accumulators數組
階段操做符是使用於db.collection.aggregate方法裏面,數組參數中的第一層。函數
db.collection.aggregate( [ { 階段操做符:表述 }, { 階段操做符:表述 }, ... ] )
表達式操做符主要用於在管道中構建表達式時使用,使用相似於函數那樣須要參數,主要用於$project操做符中,用於構建表達式,使用方法通常以下:this
方法1:翻譯
{ <operator>: [ <argument1>, <argument2> ... ] }
方法2:code
{ <operator>: <argument> }
累加器原本只能使用與$groud下,可是版本3.2或以上,部分累加器還能使用於$project。當在$group中使用時,累加器是針對每一個分組使用的;當在$project中使用時,累加器則是針對每一個字面量起做用,具體用法下一篇文章闡述。
因爲操做符比較多,本篇文章先說第一類階段操做符,後面兩類在下一篇再說。
操做符 | 簡述 |
---|---|
$match | 匹配操做符,用於對文檔集合進行篩選 |
$project | 投射操做符,用於重構每個文檔的字段,能夠提取字段,重命名字段,甚至能夠對原有字段進行操做後新增字段 |
$sort | 排序操做符,用於根據一個或多個字段對文檔進行排序 |
$limit | 限制操做符,用於限制返回文檔的數量 |
$skip | 跳過操做符,用於跳過指定數量的文檔 |
$count | 統計操做符,用於統計文檔的數量 |
$group | 分組操做符,用於對文檔集合進行分組 |
$unwind | 拆分操做符,用於將數組中的每個值拆分爲單獨的文檔 |
$lookup | 鏈接操做符,用於鏈接同一個數據庫中另外一個集合,並獲取指定的文檔,相似於populate |
更多操做符介紹詳見官網:https://docs.mongodb.com/manual/reference/operator/aggregation/
假設有一個保存用戶的集合Users,一個文章的集合Articles,數據大體以下:
users:
[ { name: 'John', age: 16, sex: male, city: guangzhou, _id: 1, ...}, { name: 'Rose', age: 18, sex: female, city: beijing, _id: 2, ...}, { name: 'Jack', age: 29, sex: male, city: guangzhou, _id: 3, ...}, { name: 'Allen', age: 18, sex: female, city: beijing, _id: 4, ...}, { name: 'Cruz', age: 22, sex: male, city: guangzhou, _id: 5, ...}, { name: 'Peter', age: 18, sex: male, city: guangzhou, _id: 6, ...}, { name: 'Kelly', age: 23, sex: female, city: shanghai, _id: 7, ...}, ... ]
articles:
[ { title: 'this is article A', author: 'John', _id: 1, ... }, { title: 'this is article B', author: 'Jack', _id: 2, ... }, { title: 'this is article C', author: 'Rose', _id: 3, ... }, { title: 'this is article D', author: 'John', _id: 4, ... }, { title: 'this is article E', author: 'John', _id: 5, ... }, ... ]
用於重構每個文檔的字段,能夠提取字段,重命名字段,甚至能夠對原有字段進行操做後新增字段
{ $match: { <query> } }
db.users.aggregate([{ $match : { age : "18" } }]);
用於對文檔集合進行篩選
{ $project: { <specification(s)> } }
specification的規則
規則 | 描述 |
---|---|
<字段名>: 1 or true | 選擇須要返回什麼字段 |
_id: 0 or false | 不返回_id(默認返回) |
<字段名>: 表達式 | 使用表達式,能夠用於重命名字段,或對其值進行操做,或新增字段 |
<字段名>: 0 or false | 選擇須要不返回什麼字段,注意:當使用這種用法時,就不要用上面的方法 |
db.users.aggregate([{ $project : { name: 1 } }]);
db.users.aggregate([{ $project : { ueserId: '$_id', _id: 0 } }]);
db.users.aggregate([ { $project : { name: 1, username: { $toUpper: '$name' }, _id: 0 } } ]);
關於管道表達式:最簡單的「$project」表達式是包含和排除字段(如: { name: 1 }),以及字段名稱$fieldname(如: { userId: '$_id' })。除此之外,還可使用表達式操做符(如: $toUpper)構成更豐富的表達式,將多個字面量和變量組合在一塊兒使用,獲得更多有意思的值,更多表達式操做符的說明及使用在另外的篇章中詳細闡述。
用於根據一個或多個字段對文檔進行排序
{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }
db.users.aggregate([{ $sort : { age: 1 } }]);
用於限制返回文檔的數量
{ $limit: <positive integer> }
db.articles.aggregate({ $limit : 3 });
用於跳過指定數量的文檔
{ $skip: <positive integer> }
db.users.aggregate([{ $skip : 1 }]);
用於統計文檔的數量
{ $count: <string> }
string是統計以後輸出統計結果的字段名
db.articles.aggregate([{ totalArticle : 1 }]);
用於對文檔集合進行分組
{ $group: { _id: <expression>, <field1>: { <accumulator1> : <expression1> }, ... } }
_id是必須的,用做分組的依據條件
db.users.aggregate([{ $group : { _id: '$sex' } }]);
返回結果:
[ { _id: 'male' }, { _id: 'female' } ]
db.users.aggregate([ { $group : { _id: '$sex', avgAge: { $avg: '$age' }, conut: { $sum: 1 } } } ]);
返回結果:
[ { _id: 'male', avgAge: <男性平均年齡>, count: <男性人數> }, { _id: 'female', avgAge: <女性平均年齡>, count: <女性人數> } ]
此處用到的表達式 { $avg: '$age' } 用於求平均年齡,$avg是求均值的操做符,$sum用於彙總, 都只能在$group中使用的累加器,mongoDB3.2以上版本則還能夠在$project中使用,詳細會在另外的篇章中闡述。
用於將數組中的每個值拆分爲單獨的文檔
{ $unwind: <field path> }
增長icludeArrayIndex,preserveNullAndEmptyArrays兩個可選配置
{ $unwind: { path: <field path>, includeArrayIndex: <string>, preserveNullAndEmptyArrays: <boolean> } }
字段 | 類型 | 描述 |
---|---|---|
path | string | 必填,數組的字段名,指定須要拆分的字段 |
includeArrayIndex | string | 可選,定義返回的字段名,返回的值是拆分前值在原數組的位置 |
preserveNullAndEmptyArrays | boolean | 可選,配置在path的值爲空或缺失的狀況下是否拆分, 默認false |
假設articles文檔集合是這樣:
{ title: 'this is article A', author: 'John', _id: 1, comments: ['a', 'b', 'c']}
db.articles.aggregate([{ $unwind: '$comments' }]);
結果:
[ { title: 'this is article A', author: 'John', _id: 1, comments: 'a'}, { title: 'this is article A', author: 'John', _id: 1, comments: 'b'}, { title: 'this is article A', author: 'John', _id: 1, comments: 'c'}, ]
假設articles文檔集合是這樣:
[ { title: 'this is article A', author: 'John', _id: 1, comments: ['a', 'b', 'c'] } { title: 'this is article B', author: 'Jack', _id: 2 }, { title: 'this is article C', author: 'Amy', _id: 3, comments: [] }, { title: 'this is article D', author: 'Lam', _id: 4, comments: null }, ]
操做:
db.articles.aggregate([ { $unwind: { path: '$comments', includeArrayIndex: 'arrayIndex', } } ]);
結果:
[ { title: 'this is article A', author: 'John', _id: 1, comments: 'a', arrayIndex: NumberLong(0) }, { title: 'this is article A', author: 'John', _id: 1, comments: 'b', arrayIndex: NumberLong(1) }, { title: 'this is article A', author: 'John', _id: 1, comments: 'c', arrayIndex: NumberLong(2) }, ]
操做:
db.articles.aggregate([ { $unwind: { path: '$comments', preserveNullAndEmptyArrays: true, } } ]);
結果:
[ { title: 'this is article A', author: 'John', _id: 1, comments: 'a' }, { title: 'this is article A', author: 'John', _id: 1, comments: 'b' }, { title: 'this is article A', author: 'John', _id: 1, comments: 'c' }, { title: 'this is article B', author: 'Jack', _id: 2 }, { title: 'this is article C', author: 'Amy', _id: 3 }, { title: 'this is article C', author: 'Amy', _id: 3, comments: null } ]
用於鏈接同一個數據庫中另外一個集合,並獲取指定的文檔,相似於populate
{ $lookup: { from: <collection to join>, localField: <field from the input documents>, foreignField: <field from the documents of the "from" collection>, as: <output array field> } }
字段 | 描述 |
---|---|
from | 須要關聯的集合名 |
localField | 本集合中須要查找的字段 |
foreignField | 另一個集合中須要關聯的字段 |
as | 輸出的字段名 |
db.articles.aggregate([ { $lookup: { from: "users", localField: "author", foreignField: "name", as: "author" } } ])
結果:
[ { title: 'this is article A', author: { name: 'John', age: 16, sex: male, city: guangzhou, _id: 1, ... }, _id: 1, ... }, { title: 'this is article B', author: { name: 'Jack', age: 29, sex: male, city: guangzhou, _id: 3, ... }, _id: 2, ... }, { title: 'this is article C', author: { name: 'Rose', age: 18, sex: male, city: beijing, _id: 2, ... }, _id: 3, ... }, { title: 'this is article D', author: { name: 'John', age: 16, sex: male, city: guangzhou, _id: 1, ... }, _id: 4, ... }, { title: 'this is article E', author: { name: 'John', age: 16, sex: male, city: guangzhou, _id: 1, ... }, _id: 5, ... }, ... ]
找出發表文章最多的5位做者,按發表文章排序,顯示他的發表文章的總次數,和他本身的信息
db.articles.aggregate([ { $group: { _id: "$author", count: { $sum: 1 }, } }, { $sort: { count: -1 } }, { $skip: 5 }, { $lookup: { from: "users", localField: "author", foreignField: "name", as: "author" } }, { $project: { _id: 0, } } ])
本文介紹了幾個使用聚合管道查詢時經常使用的管道操做符的用法,熟練地綜合使用以上操做符能夠對數據進行多樣的處理,組合,統計,得出多樣化的數據。另外再加以配合表達式操做符(Expression Operators)組成的表達式, 或者在$project或$group中使用累加器(Accumulators)能查詢統計的內容會更加的多樣化。
感謝閱讀~